diff --git a/contracts/BorrowerOperations.sol b/contracts/BorrowerOperations.sol index 7a7e525..9f297a2 100644 --- a/contracts/BorrowerOperations.sol +++ b/contracts/BorrowerOperations.sol @@ -17,6 +17,8 @@ import "./BorrowerOperationsStorage.sol"; import "./Dependencies/Mynt/MyntLib.sol"; import "./Interfaces/IPermit2.sol"; import "./Interfaces/perimeter/IExitFeeController.sol"; +import "./Interfaces/perimeter/IExitDelayQueueHook.sol"; +import "./Dependencies/BorrowerOperationsPerimeterOps.sol"; contract BorrowerOperations is LiquityBase, @@ -37,7 +39,17 @@ contract BorrowerOperations is bytes32 private constant PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS = keccak256("PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS"); + // --- Security-perimeter exit-delay hook --- + // The delay queue pointer also lives in an EIP-1967-style unstructured + // slot, so `BorrowerOperations` storage-layout is unchanged (zero-diff). It is + // rotated with `setExitDelayQueue` under the SAME owner as the controller + // pointer. Because the pointer redirects ESCROW it is more sensitive than the + // controller pointer — rotation is an Owner/SIP action. + bytes32 private constant EXIT_DELAY_QUEUE_SLOT = + bytes32(uint256(keccak256("sovryn.perimeterExitDelayQueue")) - 1); + event ExitFeeControllerSet(address indexed previous, address indexed current); + event ExitDelayQueueSet(address indexed previous, address indexed current); event ExitFeeApplied( bytes32 indexed surfaceId, address indexed actor, @@ -817,78 +829,26 @@ contract BorrowerOperations is } /** - * Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode, - * charging the Perimeter exit fee when the PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS policy is active. - * Fail-open like every Perimeter hook: on any Perimeter failure (controller missing/ - * reverting, invalid quote, fee-leg transfer failure inside the pool) the claimant - * receives the full surplus — a Perimeter failure can never brick a claim. The - * non-charging path is the untouched claimColl flow (plus the ExitFeeSkipped - * event, same convention as _sendCollWithExitFee). + * Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in + * Recovery Mode, settled through the security perimeter: the exit fee leg when the + * PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS policy is active, then the delay leg. + * + * The FEE leg is fail-open, as every Perimeter fee hook is: a missing or reverting + * controller, an invalid quote or a failed fee transfer leaves the claimant with the + * full surplus. The DELAY leg is fail-CLOSED: once the perimeter resolves a hold the + * net must escrow, so an unwired or reverting queue reverts the claim and the claimant + * keeps their surplus balance to claim again later. + * + * With no fee and no delay this is the untouched claimColl flow, plus the + * ExitFeeSkipped event. */ function claimCollateral() external override { - uint256 gross = collSurplusPool.getCollateral(msg.sender); - // Single Zero deployment: subProduct = address(0). Asset is native RBTC. - IExitFeeController.ExitFeeQuote memory q = _safeQuote( - PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, - address(0), - msg.sender, - gross + _delegateToPerimeterOps( + abi.encodeWithSelector( + BorrowerOperationsPerimeterOps(address(0)).claimSurplusWithPerimeter.selector, + collSurplusPool + ) ); - - // Defensive: a quote that charges into address(0) would burn the fee (a - // value call to a no-code address succeeds). Demote to the non-charging - // path — DISABLED is the enum's "feeReceiver == address(0)" reason. - if (q.active && q.feeAmount > 0 && q.feeReceiver == address(0)) { - q.active = false; - q.netAmount = gross; - q.reason = uint8(IExitFeeController.SkipReason.DISABLED); - } - - if (q.active && q.feeAmount > 0) { - // Two-leg split inside the pool (fee → feeReceiver, net → claimant); - // the pool's fee leg is fail-open and reports which event is truthful. - bool feePaid = collSurplusPool.claimCollWithFee( - msg.sender, - q.feeReceiver, - q.feeAmount - ); - if (feePaid) { - emit ExitFeeApplied( - PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, - msg.sender, - address(0), - address(0), - msg.sender, - gross, - q.feeAmount, - q.netAmount, - q.feeReceiver - ); - } else { - emit ExitFeeSkipped( - PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, - msg.sender, - address(0), - gross, - q.rateBps, - uint8(IExitFeeController.SkipReason.VAULT_REVERT) - ); - } - } else { - // !active (INACTIVE / DISABLED / INVALID_QUOTE / CONTROLLER_REVERT) - // OR active-but-zero-fee (dust / zero-rate / gross == 0 → reason NONE). - emit ExitFeeSkipped( - PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, - msg.sender, - address(0), - gross, - q.rateBps, - q.reason - ); - // send ETH from CollSurplus Pool to owner — untouched original path - // (gross == 0 falls through to claimColl's own revert, identical to today) - collSurplusPool.claimColl(msg.sender); - } } // --- Helper functions --- @@ -1004,6 +964,86 @@ contract BorrowerOperations is emit ExitFeeControllerSet(prev, ctrl); } + /// @notice Address of the ExitDelayQueue this instance escrows delayed + /// collateral exits into. Held in an EIP-1967-style unstructured slot + /// (no regular-storage footprint). address(0) until governance pins + /// one ⇒ the security-perimeter reroute is unwired ⇒ exits pay direct + /// at `d == 0` and fail CLOSED at `d > 0` (a delay is never silently + /// bypassed by a missing pointer). + function exitDelayQueue() public view returns (address queue) { + bytes32 slot = EXIT_DELAY_QUEUE_SLOT; + assembly { + queue := sload(slot) + } + } + + /// @notice Pin/rotate the ExitDelayQueue pointer. `onlyOwner` — the same + /// BorrowerOperations proxy owner (= TimelockOwner on mainnet) that + /// gates `setExitFeeController`. Because the pointer redirects ESCROW + /// it is MORE sensitive than the controller pointer; rotation is an + /// Owner/SIP action. Reverts on a non-contract so a typo cannot point + /// the reroute at a no-code address (address(0) is likewise rejected — + /// unwiring, if ever needed, is a deliberate distinct governance path, + /// and the perimeter is instead disabled via the controller kill + /// switch, which quotes `d == 0` and pays direct). + function setExitDelayQueue(address queue) external onlyOwner { + require(queue != address(0), "EDQ:zero"); + checkContract(queue); + address prev = exitDelayQueue(); + bytes32 slot = EXIT_DELAY_QUEUE_SLOT; + assembly { + sstore(slot, queue) + } + emit ExitDelayQueueSet(prev, queue); + } + + /// @dev Fail-CLOSED delay quote wrapper. Resolves the single hook + /// entry `quoteExitDelayFor` on the shared Perimeter controller and returns + /// `(d, effOrig, effOwner)`. Two levels, deliberately distinct: + /// 1. controller-POINTER lookup is FAIL-OPEN — a missing OR code-less + /// controller ⇒ perimeter unwired ⇒ `(0, raw, raw)` ⇒ pay direct + /// (mirrors the fee path; also, 0.6.11 try/catch does NOT catch a + /// call to a no-code address, so the extcodesize guard is required); + /// 2. once a controller is resolved, the `quoteExitDelayFor` CALL is + /// FAIL-CLOSED — a revert reverts the whole exit and MUST NOT be + /// interpreted as `d = 0`-direct (that would silently disable the + /// perimeter — the hazard this guards against). Uses a DISTINCT revert selector for + /// halt monitoring. + /// The `!securityPerimeterEnabled` short-circuit is the FIRST statement + /// inside `quoteExitDelayFor`, so a healthy-but-disabled perimeter returns + /// `(0, raw, owner)` normally (liveness escape). The hook ignores + /// `effOrig`/`effOwner` whenever `d == 0`. + function _safeQuoteExitDelay( + address rawOriginator, + address owner, + address receiver + ) private view returns (uint32 d, address effOrig, address effOwner) { + address ctrl = exitFeeController(); + uint256 ctrlSize; + assembly { + ctrlSize := extcodesize(ctrl) + } + // Level 1 — FAIL-OPEN pointer lookup: unwired/unreachable ⇒ direct pay. + // Raw identities are returned but the caller ignores them when d == 0. + if (ctrl == address(0) || ctrlSize == 0) { + return (0, rawOriginator, owner); + } + // Level 2 — FAIL-CLOSED quote: a controller revert reverts the exit. + try + IExitFeeController(ctrl).quoteExitDelayFor( + rawOriginator, + owner, + receiver, + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + address(0) + ) + returns (uint32 d_, address effOrig_, address effOwner_) { + return (d_, effOrig_, effOwner_); + } catch { + revert("PERIMETER:delay-quote-failed"); + } + } + /// @dev Fail-open quote wrapper. On a missing/reverting controller or a /// semantically invalid quote, returns a non-charging quote with /// `netAmount == gross`. The validity gate uses subtraction only @@ -1057,76 +1097,53 @@ contract BorrowerOperations is } } - /// @dev Settle a borrower collateral payout, charging the Perimeter exit fee - /// when the resolved policy is active. The fee leg uses `try/catch` - /// (0.6.11 native) so a fee-receiver failure never bricks the exit; on - /// any non-charging path the full `gross` is sent to the borrower via - /// the existing fail-closed `sendETH`. ActivePool's recorded ETH - /// decrements by exactly `gross` either way (the reverted fee-leg - /// subcall rolls back its `ETH.sub`). + /// @dev Settle a borrower collateral payout through the security perimeter: + /// the fee leg, then the delay leg. The body runs in + /// `BorrowerOperationsPerimeterOps` under `delegatecall`, so it settles + /// in this proxy's context and the same transaction, and its events + /// carry this address. + /// + /// Any failure propagates unchanged. Once the perimeter resolves a + /// delay the leg must escrow, so a reverting hook reverts the whole + /// close or adjust rather than paying direct. function _sendCollWithExitFee( IActivePool _activePool, address borrower, uint256 gross ) private { - // Debt-only adjustments (repay / debt-decrease) reach here with gross == 0: - // no collateral leaves the pool, so there is nothing to settle. Skip the - // controller round-trip and the Perimeter event. (Baseline called - // sendETH(borrower, 0) here — a value-less no-op that only emitted - // EtherSent(_, 0) / ActivePoolETHBalanceUpdated; we drop that redundant - // transfer, so debt-only ops emit fewer events than pre-Perimeter.) - if (gross == 0) { - return; - } - - // Single Zero deployment: subProduct = address(0). Asset is native RBTC. - IExitFeeController.ExitFeeQuote memory q = _safeQuote( - PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, - address(0), - borrower, - gross + _delegateToPerimeterOps( + abi.encodeWithSelector( + BorrowerOperationsPerimeterOps(address(0)).sendCollWithExitFee.selector, + _activePool, + borrower, + gross + ) ); + } - if (q.active && q.feeAmount > 0) { - try _activePool.sendETH(q.feeReceiver, q.feeAmount) { - _activePool.sendETH(borrower, q.netAmount); // user leg: existing fail-closed behavior - // Emit only after BOTH legs settle, so an ExitFeeApplied event always - // implies a completed borrower payout (truthful by construction). - emit ExitFeeApplied( - PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, - borrower, - address(0), - address(0), - borrower, - gross, - q.feeAmount, - q.netAmount, - q.feeReceiver - ); - return; - } catch { - emit ExitFeeSkipped( - PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, - borrower, - address(0), - gross, - q.rateBps, - uint8(IExitFeeController.SkipReason.VAULT_REVERT) - ); + /// @dev Run one perimeter settlement in this proxy's context and transaction. + /// Any failure propagates unchanged, so a reverting settlement reverts + /// the whole close, adjust or claim rather than paying direct. + /// + /// `checkContract` is what makes that true: a `delegatecall` to a + /// code-less address SUCCEEDS with empty returndata, so an unset hook + /// would otherwise skip the fee and the delay in silence. + function _delegateToPerimeterOps(bytes memory payload) private { + address ops = perimeterOps; + checkContract(ops); + (bool ok, bytes memory ret) = ops.delegatecall(payload); + if (!ok) { + assembly { + revert(add(ret, 0x20), mload(ret)) } - } else { - // !active (INACTIVE / DISABLED / INVALID_QUOTE / CONTROLLER_REVERT) - // OR active-but-zero-fee (dust / zero-rate policy → q.reason == NONE). - emit ExitFeeSkipped( - PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, - borrower, - address(0), - gross, - q.rateBps, - q.reason - ); } - _activePool.sendETH(borrower, gross); // full-gross fallback (any non-charging path) + } + + /// @notice Rotate the perimeter settlement hook. `onlyOwner`, mirroring + /// `setTroveManagerRedeemOps`. + function setPerimeterOps(address _perimeterOps) external onlyOwner { + checkContract(_perimeterOps); + perimeterOps = _perimeterOps; } /// @notice Read-only preview of the Perimeter exit fee on a Zero borrower collateral diff --git a/contracts/BorrowerOperationsStorage.sol b/contracts/BorrowerOperationsStorage.sol index 9e7d769..0f9f88d 100644 --- a/contracts/BorrowerOperationsStorage.sol +++ b/contracts/BorrowerOperationsStorage.sol @@ -36,4 +36,9 @@ contract BorrowerOperationsStorage is Ownable { IMassetManager public massetManager; IFeeDistributor public feeDistributor; + + /// @notice The perimeter settlement hook `_sendCollWithExitFee` delegates to. + /// Appended last so no existing slot moves; set at init and + /// rotatable by the owner, mirroring `troveManagerRedeemOps`. + address public perimeterOps; } diff --git a/contracts/CollSurplusPool.sol b/contracts/CollSurplusPool.sol index d9e08d6..c25e64f 100644 --- a/contracts/CollSurplusPool.sol +++ b/contracts/CollSurplusPool.sol @@ -117,6 +117,50 @@ contract CollSurplusPool is CollSurplusPoolStorage, CheckContract, ICollSurplusP require(success, "CollSurplusPool: sending ETH failed"); } + /// @notice Two-leg claim that sends the remainder to `_netRecipient`. + /// Same accounting and same CEI ordering as `claimCollWithFee`: the + /// claim is resolved against `_account`'s balance, which is zeroed + /// before either external call, and the single `ETH` decrement equals + /// fee + net exactly. Only the destination of the net leg differs, so + /// the perimeter can escrow it in the exit delay queue instead of + /// paying the claimant directly. The fee leg stays fail-open and the + /// net leg fail-closed. + /// + /// `claimCollWithFee` is left exactly as deployed rather than + /// delegating here: it is the selector the shipped BorrowerOperations + /// calls, and it is the rollback target. + function claimCollWithFeeTo( + address _account, + address _feeReceiver, + uint256 _feeAmount, + address _netRecipient + ) external override returns (bool feePaid, uint256 netAmount) { + _requireCallerIsBorrowerOperations(); + require(_netRecipient != address(0), "CollSurplusPool: zero net recipient"); + uint256 claimableColl = balances[_account]; + require(claimableColl > 0, "CollSurplusPool: No collateral available to claim"); + require(_feeAmount <= claimableColl, "CollSurplusPool: fee exceeds claimable"); + + balances[_account] = 0; + emit CollBalanceUpdated(_account, 0); + + ETH = ETH.sub(claimableColl); + + // A zero fee takes no leg at all: a zero-value call would report a fee + // that was never charged, and an uncharged claim can still be delayed. + if (_feeAmount > 0) { + (feePaid, ) = _feeReceiver.call{ value: _feeAmount, gas: FEE_LEG_GAS_CAP }(""); + if (feePaid) { + emit EtherSent(_feeReceiver, _feeAmount); + } + } + netAmount = feePaid ? claimableColl.sub(_feeAmount) : claimableColl; + + emit EtherSent(_netRecipient, netAmount); + (bool success, ) = _netRecipient.call{ value: netAmount }(""); + require(success, "CollSurplusPool: sending ETH failed"); + } + // --- 'require' functions --- function _requireCallerIsBorrowerOperations() internal view { diff --git a/contracts/DefaultPool.sol b/contracts/DefaultPool.sol index 8d8076f..b671b33 100644 --- a/contracts/DefaultPool.sol +++ b/contracts/DefaultPool.sol @@ -24,10 +24,10 @@ contract DefaultPool is DefaultPoolStorage, CheckContract, IDefaultPool { // --- Dependency setters --- - function setAddresses(address _troveManagerAddress, address _activePoolAddress) - external - onlyOwner - { + function setAddresses( + address _troveManagerAddress, + address _activePoolAddress + ) external onlyOwner { checkContract(_troveManagerAddress); checkContract(_activePoolAddress); diff --git a/contracts/Dependencies/BaseMath.sol b/contracts/Dependencies/BaseMath.sol index 94de51b..6624fe3 100644 --- a/contracts/Dependencies/BaseMath.sol +++ b/contracts/Dependencies/BaseMath.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.6.11; - contract BaseMath { - uint constant public DECIMAL_PRECISION = 1e18; + uint public constant DECIMAL_PRECISION = 1e18; } diff --git a/contracts/Dependencies/BorrowerOperationsPerimeterOps.sol b/contracts/Dependencies/BorrowerOperationsPerimeterOps.sol new file mode 100644 index 0000000..2ac2234 --- /dev/null +++ b/contracts/Dependencies/BorrowerOperationsPerimeterOps.sol @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.11; +pragma experimental ABIEncoderV2; + +import "../Interfaces/IActivePool.sol"; +import "../Interfaces/ICollSurplusPool.sol"; +import "../Interfaces/perimeter/IExitFeeController.sol"; +import "../Interfaces/perimeter/IExitDelayQueueHook.sol"; + +/// @title BorrowerOperationsPerimeterOps +/// @notice Settles a Zero borrower collateral payout, and a surplus claim, +/// through the security perimeter: the exit fee leg, then the delay leg. +/// +/// @dev Used via `delegatecall` from BorrowerOperations, the same way +/// TroveManagerRedeemOps is used from TroveManager, so `address(this)` +/// and `msg.sender` are the caller\'s, the unstructured pointer slots it +/// reads are the caller\'s, and the events it emits carry the caller\'s +/// address. +/// +/// It declares NO STORAGE and inherits none, deliberately. A companion +/// that inherited BorrowerOperationsStorage would appear to share the +/// caller\'s variables while its slots sat four words earlier, because +/// BorrowerOperations also inherits LiquityBase and this contract does +/// not: reading `collSurplusPool` here would return +/// BorrowerOperations\' `liquityBaseParams`. Everything this contract +/// needs from the caller\'s state therefore arrives as an argument, and +/// only the two EIP-1967-style slots — whose addresses are constants, +/// not declaration order — are read directly. +contract BorrowerOperationsPerimeterOps { + bytes32 private constant EXIT_FEE_CONTROLLER_SLOT = + bytes32(uint256(keccak256("sovryn.perimeterExitFeeController")) - 1); + bytes32 private constant EXIT_DELAY_QUEUE_SLOT = + bytes32(uint256(keccak256("sovryn.perimeterExitDelayQueue")) - 1); + bytes32 private constant PERIMETER_SURFACE_ZERO_WITHDRAW_COLL = + keccak256("PERIMETER_SURFACE_ZERO_WITHDRAW_COLL"); + bytes32 private constant PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS = + keccak256("PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS"); + + event ExitFeeApplied( + bytes32 indexed surfaceId, + address indexed actor, + address indexed asset, + address subProduct, + address recipient, + uint256 grossAmount, + uint256 feeAmount, + uint256 netAmount, + address feeReceiver + ); + event ExitFeeSkipped( + bytes32 indexed surfaceId, + address indexed actor, + address indexed asset, + uint256 grossAmount, + uint16 rateBps, + uint8 reason + ); + + /// @dev Reads the caller\'s pinned controller from the shared slot. + function exitFeeController() internal view returns (address ctrl) { + bytes32 slot = EXIT_FEE_CONTROLLER_SLOT; + assembly { + ctrl := sload(slot) + } + } + + /// @dev Reads the caller\'s pinned queue from the shared slot. + function exitDelayQueue() internal view returns (address queue) { + bytes32 slot = EXIT_DELAY_QUEUE_SLOT; + assembly { + queue := sload(slot) + } + } + + /// @dev Settle a borrower collateral payout, charging the Perimeter exit fee + /// when the resolved policy is active. The fee leg uses `try/catch` + /// (0.6.11 native) so a fee-receiver failure never bricks the exit; on + /// any non-charging path the full `gross` is sent to the borrower via + /// the existing fail-closed `sendETH`. ActivePool's recorded ETH + /// decrements by exactly `gross` either way (the reverted fee-leg + /// subcall rolls back its `ETH.sub`). + function sendCollWithExitFee( + IActivePool _activePool, + address borrower, + uint256 gross + ) external { + // Debt-only adjustments (repay / debt-decrease) reach here with gross == 0: + // no collateral leaves the pool, so there is nothing to settle. Skip the + // controller round-trip and the Perimeter event. (Baseline called + // sendETH(borrower, 0) here — a value-less no-op that only emitted + // EtherSent(_, 0) / ActivePoolETHBalanceUpdated; we drop that redundant + // transfer, so debt-only ops emit fewer events than pre-Perimeter.) + if (gross == 0) { + return; + } + + // Security-perimeter delay quote — computed ONCE up-front so a single `d` + // governs the WHOLE exit: a fee-vault failure still escrows GROSS + // behind the delay and cannot bypass it. FAIL-CLOSED (except the + // kill-switch / unwired short-circuit): a controller revert reverts the + // exit. Zero has no passthrough, so originator == owner == receiver + // == borrower (== msg.sender on every collateral-out path). The queue is + // NEVER touched here — only inside the `d > 0` branch of `_payUserColl` + //. + DelayLeg memory dl; + (dl.d, dl.effOrig, dl.effOwner) = _safeQuoteExitDelay( + borrower, + borrower, + borrower, + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL + ); + + // Single Zero deployment: subProduct = address(0). Asset is native RBTC. + IExitFeeController.ExitFeeQuote memory q = _safeQuote( + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + address(0), + borrower, + gross + ); + + if (q.active && q.feeAmount > 0) { + try _activePool.sendETH(q.feeReceiver, q.feeAmount) { + // user leg (net): direct-pay OR reroute to the delay queue when d>0 + _payUserColl(_activePool, borrower, q.netAmount, dl); + // Emit only after BOTH legs settle, so an ExitFeeApplied event always + // implies a completed borrower payout (truthful by construction). + emit ExitFeeApplied( + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + borrower, + address(0), + address(0), + borrower, + gross, + q.feeAmount, + q.netAmount, + q.feeReceiver + ); + return; + } catch { + emit ExitFeeSkipped( + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + borrower, + address(0), + gross, + q.rateBps, + uint8(IExitFeeController.SkipReason.VAULT_REVERT) + ); + } + } else { + // !active (INACTIVE / DISABLED / INVALID_QUOTE / CONTROLLER_REVERT) + // OR active-but-zero-fee (dust / zero-rate policy → q.reason == NONE). + emit ExitFeeSkipped( + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + borrower, + address(0), + gross, + q.rateBps, + q.reason + ); + } + // full-gross fallback (any non-charging path): direct-pay OR reroute to the + // delay queue when d>0 — the same up-front `d` governs both legs. + _payUserColl(_activePool, borrower, gross, dl); + } + + /// @dev Settle the (post-fee) borrower USER leg of a voluntary collateral-out. + /// When the perimeter quotes no delay (`d == 0`) this is the EXISTING + /// native payout, byte-for-byte unchanged (`sendETH(receiver, amount)`). + /// When `d > 0` the leg is rerouted into the ExitDelayQueue: ActivePool + /// PUSHES the native RBTC to the queue, immediately followed by + /// `recordReceivedNativeExit` in the SAME outer tx — both INSIDE this + /// `d > 0` branch so the queue is never touched until a delay is + /// established off-queue, and a record revert rolls back the push + /// (fail-CLOSED: after the trove state already mutated, the whole + /// close/adjust reverts atomically — a bricked queue blocks Zero closes + /// until the kill switch is flipped). The queue's `receive()` is + /// unconditional and, via measured-receipt, credits EXACTLY `amount` when + /// its surplus `>= amount` — a donation cannot brick the record. + function _payUserColl( + IActivePool _activePool, + address receiver, + uint256 amount, + DelayLeg memory dl + ) private { + // A net leg can be 0 on a full-fee edge; nothing to pay or escrow. + if (amount == 0) { + return; + } + + if (dl.d > 0) { + address queue = exitDelayQueue(); + // FAIL-CLOSED: once the perimeter quotes d>0 the user leg MUST escrow. + // An unwired queue reverts the exit with a DISTINCT selector (halt + // monitoring) — a delay can never be silently bypassed by a missing + // pointer. + require(queue != address(0), "PERIMETER:queue-unset"); + require(amount <= uint256(uint128(-1)), "PERIMETER:amount-too-large"); + + // PUSH native to the queue (reuses the existing fail-closed sendETH + // primitive — ActivePool.ETH decrements by exactly `amount`, identical + // to the direct payout), then measured-record in the SAME outer tx. + _activePool.sendETH(queue, amount); + IExitDelayQueueHook(queue).recordReceivedNativeExit( + uint128(amount), + dl.d, + PERIMETER_SURFACE_ZERO_WITHDRAW_COLL, + address(0), + dl.effOrig, + dl.effOwner, + receiver + ); + } else { + _activePool.sendETH(receiver, amount); // EXISTING native payout, unchanged + } + } + + /// @notice Settle a surplus claim through the perimeter: the fee leg, then + /// the delay leg. + /// + /// @dev The claimant is `msg.sender`, preserved across the delegatecall + /// from BorrowerOperations. The pool arrives as an argument because + /// this contract declares no storage and cannot read the caller's. + /// + /// The delay is quoted ONCE, up front, so a fee-vault failure still + /// escrows the gross behind the hold and cannot bypass it — the same + /// rule the collateral exit follows. + /// + /// When the perimeter imposes no delay this is the existing claim, + /// unchanged: `claimCollWithFee` on the charging path and the + /// untouched `claimColl` otherwise, both paying the claimant + /// directly. When it does, the pool sends the net leg to the queue + /// instead and the record follows in the same transaction. A record + /// failure reverts the whole claim, so a hold can never be silently + /// skipped; the claimant keeps their surplus balance and can claim + /// again once the queue is healthy. + function claimSurplusWithPerimeter(ICollSurplusPool pool) external { + address claimant = msg.sender; + uint256 gross = pool.getCollateral(claimant); + + // FAIL-CLOSED: a controller revert reverts the claim. Zero has no + // passthrough, so originator == owner == receiver == the claimant. + DelayLeg memory dl; + (dl.d, dl.effOrig, dl.effOwner) = _safeQuoteExitDelay( + claimant, + claimant, + claimant, + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS + ); + + // Single Zero deployment: subProduct = address(0). Asset is native RBTC. + IExitFeeController.ExitFeeQuote memory q = _safeQuote( + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, + address(0), + claimant, + gross + ); + + // A quote that charges into address(0) would burn the fee, because a + // value call to a no-code address succeeds. Demote to the non-charging + // path; DISABLED is the enum's "feeReceiver == address(0)" reason. + if (q.active && q.feeAmount > 0 && q.feeReceiver == address(0)) { + q.active = false; + q.netAmount = gross; + q.reason = uint8(IExitFeeController.SkipReason.DISABLED); + } + + address netRecipient = claimant; + if (dl.d > 0) { + netRecipient = exitDelayQueue(); + // FAIL-CLOSED: once the perimeter quotes d>0 the net leg MUST escrow. + // An unwired queue reverts the claim with a DISTINCT selector — a + // hold can never be bypassed by a missing pointer. + require(netRecipient != address(0), "PERIMETER:queue-unset"); + } + + if (q.active && q.feeAmount > 0) { + // Two-leg split inside the pool (fee -> feeReceiver, net -> recipient); + // the pool's fee leg is fail-open and reports which event is truthful. + (bool feePaid, uint256 netAmount) = pool.claimCollWithFeeTo( + claimant, + q.feeReceiver, + q.feeAmount, + netRecipient + ); + _recordSurplusExit(netRecipient, netAmount, claimant, dl); + if (feePaid) { + emit ExitFeeApplied( + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, + claimant, + address(0), + address(0), + claimant, + gross, + q.feeAmount, + q.netAmount, + q.feeReceiver + ); + } else { + emit ExitFeeSkipped( + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, + claimant, + address(0), + gross, + q.rateBps, + uint8(IExitFeeController.SkipReason.VAULT_REVERT) + ); + } + return; + } + + // !active (INACTIVE / DISABLED / INVALID_QUOTE / CONTROLLER_REVERT) OR + // active-but-zero-fee (dust / zero-rate / gross == 0 -> reason NONE). + emit ExitFeeSkipped( + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, + claimant, + address(0), + gross, + q.rateBps, + q.reason + ); + if (dl.d > 0) { + (, uint256 netAmount) = pool.claimCollWithFeeTo(claimant, address(0), 0, netRecipient); + _recordSurplusExit(netRecipient, netAmount, claimant, dl); + } else { + // Untouched original path. A zero surplus falls through to + // claimColl's own revert, identical to a claim without the perimeter. + pool.claimColl(claimant); + } + } + + /// @dev Record a surplus net leg the pool has just pushed into the queue. + /// A no-delay claim never reaches the queue, and a fully-charged claim + /// (net == 0) has nothing to escrow — the queue rejects a zero amount, + /// and there is no exit for the claimant to execute later. + function _recordSurplusExit( + address queue, + uint256 netAmount, + address claimant, + DelayLeg memory dl + ) private { + if (dl.d == 0 || netAmount == 0) { + return; + } + require(netAmount <= uint256(uint128(-1)), "PERIMETER:amount-too-large"); + IExitDelayQueueHook(queue).recordReceivedNativeExit( + uint128(netAmount), + dl.d, + PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS, + address(0), + dl.effOrig, + dl.effOwner, + claimant + ); + } + + /// @dev Fail-open quote wrapper. On a missing/reverting controller or a + /// semantically invalid quote, returns a non-charging quote with + /// `netAmount == gross`. The validity gate uses subtraction only + /// (`feeAmount > gross`), never an unchecked addition, and recomputes + /// `netAmount = gross - feeAmount` so the fee + user legs always sum to + /// exactly `gross` — protecting ActivePool liquidity from a bad or + /// upgraded controller. + function _safeQuote( + bytes32 surfaceId, + address subProduct, + address actor, + uint256 gross + ) private view returns (IExitFeeController.ExitFeeQuote memory q) { + address ctrl = exitFeeController(); + // Fail open on a missing OR code-less controller. The address(0) check + // alone is not enough: a high-level call to any no-code address (EOA, + // or a controller that self-destructed after being set) reverts with + // "function call to a non-contract account", which 0.6.11 try/catch + // does NOT catch — so guard on extcodesize before the call. + uint256 ctrlSize; + assembly { + ctrlSize := extcodesize(ctrl) + } + if (ctrl == address(0) || ctrlSize == 0) { + q.netAmount = gross; + q.reason = uint8(IExitFeeController.SkipReason.CONTROLLER_REVERT); + return q; + } + try IExitFeeController(ctrl).quoteExitFee(surfaceId, subProduct, actor, gross) returns ( + IExitFeeController.ExitFeeQuote memory got + ) { + // Pool conservation is the consumer's own concern: it holds exactly `gross` + // wei to distribute, so it must never be asked to pay out more. A + // feeAmount > gross would underflow the net recompute below (bricking the + // exit) and a fee leg > gross could draw OTHER troves' collateral out of + // ActivePool. Rate, receiver, and fee policy are the configured + // controller's responsibility — not re-validated here. + if (got.feeAmount > gross) { + // Override only the verdict; leave the controller's raw feeAmount / + // rateBps / feeReceiver intact (active=false gates charging downstream). + got.active = false; + got.netAmount = gross; // non-charging shape: net == gross + got.reason = uint8(IExitFeeController.SkipReason.INVALID_QUOTE); + return got; + } + got.netAmount = gross - got.feeAmount; // fee + net == gross (no residue) + return got; + } catch { + q.netAmount = gross; + q.reason = uint8(IExitFeeController.SkipReason.CONTROLLER_REVERT); + } + } + + /// @dev Fail-CLOSED delay quote wrapper. Resolves the single hook + /// entry `quoteExitDelayFor` on the shared Perimeter controller and returns + /// `(d, effOrig, effOwner)`. Two levels, deliberately distinct: + /// 1. controller-POINTER lookup is FAIL-OPEN — a missing OR code-less + /// controller ⇒ perimeter unwired ⇒ `(0, raw, raw)` ⇒ pay direct + /// (mirrors the fee path; also, 0.6.11 try/catch does NOT catch a + /// call to a no-code address, so the extcodesize guard is required); + /// 2. once a controller is resolved, the `quoteExitDelayFor` CALL is + /// FAIL-CLOSED — a revert reverts the whole exit and MUST NOT be + /// interpreted as `d = 0`-direct (that would silently disable the + /// perimeter — the hazard this guards against). Uses a DISTINCT revert selector for + /// halt monitoring. + /// The `!securityPerimeterEnabled` short-circuit is the FIRST statement + /// inside `quoteExitDelayFor`, so a healthy-but-disabled perimeter returns + /// `(0, raw, owner)` normally (liveness escape). The hook ignores + /// `effOrig`/`effOwner` whenever `d == 0`. + function _safeQuoteExitDelay( + address rawOriginator, + address owner, + address receiver, + bytes32 surfaceId + ) private view returns (uint32 d, address effOrig, address effOwner) { + address ctrl = exitFeeController(); + uint256 ctrlSize; + assembly { + ctrlSize := extcodesize(ctrl) + } + // Level 1 — FAIL-OPEN pointer lookup: unwired/unreachable ⇒ direct pay. + // Raw identities are returned but the caller ignores them when d == 0. + if (ctrl == address(0) || ctrlSize == 0) { + return (0, rawOriginator, owner); + } + // Level 2 — FAIL-CLOSED quote: a controller revert reverts the exit. + try + IExitFeeController(ctrl).quoteExitDelayFor( + rawOriginator, + owner, + receiver, + surfaceId, + address(0) + ) + returns (uint32 d_, address effOrig_, address effOwner_) { + return (d_, effOrig_, effOwner_); + } catch { + revert("PERIMETER:delay-quote-failed"); + } + } + + /// @dev Bundles the resolved delay-leg fields so `_payUserColl` stays a + /// single-slot call and `_sendCollWithExitFee` does not run into the + /// 0.6.11 stack-depth limit. `d == 0` ⇒ perimeter off / bypassed / + /// unwired ⇒ pay direct. Zero surface has no passthrough, so + /// `effOrig`/`effOwner` are the raw identities. + struct DelayLeg { + uint32 d; + address effOrig; + address effOwner; + } +} diff --git a/contracts/Dependencies/CheckContract.sol b/contracts/Dependencies/CheckContract.sol index 5d6cd02..e8946ef 100644 --- a/contracts/Dependencies/CheckContract.sol +++ b/contracts/Dependencies/CheckContract.sol @@ -2,7 +2,6 @@ pragma solidity 0.6.11; - contract CheckContract { /** * @dev Check that the account is an already deployed non-destroyed contract. @@ -13,7 +12,9 @@ contract CheckContract { uint256 size; // solhint-disable-next-line no-inline-assembly - assembly { size := extcodesize(_account) } + assembly { + size := extcodesize(_account) + } require(size > 0, "Account code size cannot be zero"); } } diff --git a/contracts/Dependencies/Counters.sol b/contracts/Dependencies/Counters.sol index 672a4e0..2a0089c 100644 --- a/contracts/Dependencies/Counters.sol +++ b/contracts/Dependencies/Counters.sol @@ -25,4 +25,4 @@ library Counters { function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } -} \ No newline at end of file +} diff --git a/contracts/Dependencies/IERC20.sol b/contracts/Dependencies/IERC20.sol index 3c25c85..0093119 100644 --- a/contracts/Dependencies/IERC20.sol +++ b/contracts/Dependencies/IERC20.sol @@ -36,7 +36,9 @@ interface IERC20 { * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); /** @@ -64,12 +66,18 @@ interface IERC20 { * * Emits a {Transfer} event. */ - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); - + /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). @@ -83,4 +91,4 @@ interface IERC20 { * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); -} \ No newline at end of file +} diff --git a/contracts/Dependencies/IERC2612.sol b/contracts/Dependencies/IERC2612.sol index df31f9f..e31020d 100644 --- a/contracts/Dependencies/IERC2612.sol +++ b/contracts/Dependencies/IERC2612.sol @@ -10,7 +10,7 @@ pragma solidity 0.6.11; * message. This allows users to spend tokens without having to hold Ether. * * See https://eips.ethereum.org/EIPS/eip-2612. - * + * * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/ */ interface IERC2612 { @@ -36,9 +36,16 @@ interface IERC2612 { * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ - function permit(address owner, address spender, uint256 amount, - uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; - + function permit( + address owner, + address spender, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + /** * @dev Returns the current ERC2612 nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. @@ -46,13 +53,15 @@ interface IERC2612 { * Every successful call to {permit} increases `owner`'s nonce by one. This * prevents a signature from being used multiple times. * - * `owner` can limit the time a Permit is valid for by setting `deadline` to - * a value in the near future. The deadline argument can be set to uint(-1) to + * `owner` can limit the time a Permit is valid for by setting `deadline` to + * a value in the near future. The deadline argument can be set to uint(-1) to * create Permits that effectively never expire. */ function nonces(address owner) external view returns (uint256); - + function version() external view returns (string memory); + function permitTypeHash() external view returns (bytes32); + function domainSeparator() external view returns (bytes32); } diff --git a/contracts/Dependencies/Initializable.sol b/contracts/Dependencies/Initializable.sol index 0cdf9cc..f57da2e 100644 --- a/contracts/Dependencies/Initializable.sol +++ b/contracts/Dependencies/Initializable.sol @@ -7,7 +7,7 @@ pragma solidity 0.6.11; * * Based on OpenZeppelin's Initializable contract: * https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/core/contracts/Initializable.sol - * + * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually diff --git a/contracts/Dependencies/LiquityMath.sol b/contracts/Dependencies/LiquityMath.sol index 9f6c44d..329dc58 100644 --- a/contracts/Dependencies/LiquityMath.sol +++ b/contracts/Dependencies/LiquityMath.sol @@ -13,7 +13,7 @@ library LiquityMath { /* Precision for Nominal ICR (independent of price). Rationale for the value: * * - Making it “too high” could lead to overflows. - * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division. + * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division. * * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH, * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator. @@ -29,42 +29,45 @@ library LiquityMath { return (_a >= _b) ? _a : _b; } - /* - * Multiply two decimal numbers and use normal rounding rules: - * -round product up if 19'th mantissa digit >= 5 - * -round product down if 19'th mantissa digit < 5 - * - * Used only inside the exponentiation, _decPow(). - */ + /* + * Multiply two decimal numbers and use normal rounding rules: + * -round product up if 19'th mantissa digit >= 5 + * -round product down if 19'th mantissa digit < 5 + * + * Used only inside the exponentiation, _decPow(). + */ function decMul(uint x, uint y) internal pure returns (uint decProd) { uint prod_xy = x.mul(y); decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION); } - /* - * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n. - * - * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity. - * - * Called by two functions that represent time in units of minutes: - * 1) TroveManager._calcDecayedBaseRate - * 2) CommunityIssuance._getCumulativeIssuanceFraction - * - * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals - * "minutes in 1000 years": 60 * 24 * 365 * 1000 - * - * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be - * negligibly different from just passing the cap, since: - * - * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years - * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible - */ + /* + * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n. + * + * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity. + * + * Called by two functions that represent time in units of minutes: + * 1) TroveManager._calcDecayedBaseRate + * 2) CommunityIssuance._getCumulativeIssuanceFraction + * + * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals + * "minutes in 1000 years": 60 * 24 * 365 * 1000 + * + * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be + * negligibly different from just passing the cap, since: + * + * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years + * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible + */ function _decPow(uint _base, uint _minutes) internal pure returns (uint) { - - if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow - - if (_minutes == 0) {return DECIMAL_PRECISION;} + if (_minutes > 525600000) { + _minutes = 525600000; + } // cap to avoid overflow + + if (_minutes == 0) { + return DECIMAL_PRECISION; + } uint y = DECIMAL_PRECISION; uint x = _base; @@ -75,7 +78,8 @@ library LiquityMath { if (n % 2 == 0) { x = decMul(x, x); n = n.div(2); - } else { // if (n % 2 != 0) + } else { + // if (n % 2 != 0) y = decMul(x, y); x = decMul(x, x); n = (n.sub(1)).div(2); @@ -83,7 +87,7 @@ library LiquityMath { } return decMul(x, y); - } + } function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) { return (_a >= _b) ? _a.sub(_b) : _b.sub(_a); @@ -94,8 +98,9 @@ library LiquityMath { return _coll.mul(NICR_PRECISION).div(_debt); } // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR. - else { // if (_debt == 0) - return 2**256 - 1; + else { + // if (_debt == 0) + return 2 ** 256 - 1; } } @@ -106,8 +111,9 @@ library LiquityMath { return newCollRatio; } // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR. - else { // if (_debt == 0) - return 2**256 - 1; + else { + // if (_debt == 0) + return 2 ** 256 - 1; } } } diff --git a/contracts/Dependencies/LiquitySafeMath128.sol b/contracts/Dependencies/LiquitySafeMath128.sol index 2736ecd..bdb9483 100644 --- a/contracts/Dependencies/LiquitySafeMath128.sol +++ b/contracts/Dependencies/LiquitySafeMath128.sol @@ -11,11 +11,11 @@ library LiquitySafeMath128 { return c; } - + function sub(uint128 a, uint128 b) internal pure returns (uint128) { require(b <= a, "LiquitySafeMath128: subtraction overflow"); uint128 c = a - b; return c; } -} \ No newline at end of file +} diff --git a/contracts/Dependencies/Mynt/MyntLib.sol b/contracts/Dependencies/Mynt/MyntLib.sol index c5d89d0..8632727 100644 --- a/contracts/Dependencies/Mynt/MyntLib.sol +++ b/contracts/Dependencies/Mynt/MyntLib.sol @@ -94,13 +94,14 @@ library MyntLib { * @param _to ultimate recipient * @param _amount amount of transfer * - * @return SignatureTransferDetails struct object + * @return SignatureTransferDetails struct object */ - function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) { - ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({ - to: _to, - requestedAmount: _amount - }); + function _generateTransferDetails( + address _to, + uint256 _amount + ) private view returns (ISignatureTransfer.SignatureTransferDetails memory) { + ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer + .SignatureTransferDetails({ to: _to, requestedAmount: _amount }); return transferDetails; } diff --git a/contracts/Dependencies/Ownable.sol b/contracts/Dependencies/Ownable.sol index 922f8f9..bd6ff25 100644 --- a/contracts/Dependencies/Ownable.sol +++ b/contracts/Dependencies/Ownable.sol @@ -22,7 +22,7 @@ contract Ownable { /** * @dev Initializes the contract setting the deployer as the initial owner. */ - constructor () internal { + constructor() internal { _setOwner(msg.sender); } diff --git a/contracts/Dependencies/PriceFeed/IExternalPriceFeed.sol b/contracts/Dependencies/PriceFeed/IExternalPriceFeed.sol index aac2ea2..bbec078 100644 --- a/contracts/Dependencies/PriceFeed/IExternalPriceFeed.sol +++ b/contracts/Dependencies/PriceFeed/IExternalPriceFeed.sol @@ -2,7 +2,7 @@ pragma solidity 0.6.11; -/// @title A generic interface for external price providers +/// @title A generic interface for external price providers interface IExternalPriceFeed { /// @dev The returned price should be 18-decimal value /// @return the prive value and a boolean stating if the query was successful diff --git a/contracts/Dependencies/PriceFeed/RskOracle.sol b/contracts/Dependencies/PriceFeed/RskOracle.sol index 7a5d98c..637723b 100644 --- a/contracts/Dependencies/PriceFeed/RskOracle.sol +++ b/contracts/Dependencies/PriceFeed/RskOracle.sol @@ -8,7 +8,6 @@ interface IRSKOracle { } contract RskOracle is IExternalPriceFeed { - IRSKOracle rskOracle; constructor(address _address) public { diff --git a/contracts/Dependencies/SafeMath.sol b/contracts/Dependencies/SafeMath.sol index 04e66a6..8c02803 100644 --- a/contracts/Dependencies/SafeMath.sol +++ b/contracts/Dependencies/SafeMath.sol @@ -59,7 +59,11 @@ library SafeMath { * * _Available since v2.4.0._ */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + function sub( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; @@ -117,7 +121,11 @@ library SafeMath { * * _Available since v2.4.0._ */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + function div( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; @@ -154,7 +162,11 @@ library SafeMath { * * _Available since v2.4.0._ */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + function mod( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } diff --git a/contracts/Dependencies/TroveManagerRedeemOps.sol b/contracts/Dependencies/TroveManagerRedeemOps.sol index 2686be6..a2df35d 100644 --- a/contracts/Dependencies/TroveManagerRedeemOps.sol +++ b/contracts/Dependencies/TroveManagerRedeemOps.sol @@ -37,7 +37,10 @@ contract TroveManagerRedeemOps is TroveManagerBase { */ /** Constructor */ - constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) { + constructor( + uint256 _bootstrapPeriod, + address _permit2 + ) public TroveManagerBase(_bootstrapPeriod) { permit2 = IPermit2(_permit2); } diff --git a/contracts/Dependencies/console.sol b/contracts/Dependencies/console.sol index ef26dc2..343808d 100644 --- a/contracts/Dependencies/console.sol +++ b/contracts/Dependencies/console.sol @@ -4,1904 +4,2582 @@ pragma solidity 0.6.11; // Buidler's helper contract for console logging library console { - address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); - - function log() internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log()")); - ignored; - } function logInt(int p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(int)", p0)); - ignored; - } - - function logUint(uint p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint)", p0)); - ignored; - } - - function logString(string memory p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string)", p0)); - ignored; - } - - function logBool(bool p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool)", p0)); - ignored; - } - - function logAddress(address p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address)", p0)); - ignored; - } - - function logBytes(bytes memory p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes)", p0)); - ignored; - } - - function logByte(byte p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(byte)", p0)); - ignored; - } - - function logBytes1(bytes1 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes1)", p0)); - ignored; - } - - function logBytes2(bytes2 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes2)", p0)); - ignored; - } - - function logBytes3(bytes3 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes3)", p0)); - ignored; - } - - function logBytes4(bytes4 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes4)", p0)); - ignored; - } - - function logBytes5(bytes5 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes5)", p0)); - ignored; - } - - function logBytes6(bytes6 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes6)", p0)); - ignored; - } - - function logBytes7(bytes7 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes7)", p0)); - ignored; - } - - function logBytes8(bytes8 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes8)", p0)); - ignored; - } - - function logBytes9(bytes9 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes9)", p0)); - ignored; - } - - function logBytes10(bytes10 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes10)", p0)); - ignored; - } - - function logBytes11(bytes11 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes11)", p0)); - ignored; - } - - function logBytes12(bytes12 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes12)", p0)); - ignored; - } - - function logBytes13(bytes13 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes13)", p0)); - ignored; - } - - function logBytes14(bytes14 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes14)", p0)); - ignored; - } - - function logBytes15(bytes15 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes15)", p0)); - ignored; - } - - function logBytes16(bytes16 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes16)", p0)); - ignored; - } - - function logBytes17(bytes17 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes17)", p0)); - ignored; - } - - function logBytes18(bytes18 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes18)", p0)); - ignored; - } - - function logBytes19(bytes19 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes19)", p0)); - ignored; - } - - function logBytes20(bytes20 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes20)", p0)); - ignored; - } - - function logBytes21(bytes21 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes21)", p0)); - ignored; - } - - function logBytes22(bytes22 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes22)", p0)); - ignored; - } - - function logBytes23(bytes23 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes23)", p0)); - ignored; - } - - function logBytes24(bytes24 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes24)", p0)); - ignored; - } - - function logBytes25(bytes25 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes25)", p0)); - ignored; - } - - function logBytes26(bytes26 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes26)", p0)); - ignored; - } - - function logBytes27(bytes27 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes27)", p0)); - ignored; - } - - function logBytes28(bytes28 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes28)", p0)); - ignored; - } - - function logBytes29(bytes29 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes29)", p0)); - ignored; - } - - function logBytes30(bytes30 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes30)", p0)); - ignored; - } - - function logBytes31(bytes31 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes31)", p0)); - ignored; - } - - function logBytes32(bytes32 p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes32)", p0)); - ignored; - } - - function log(uint p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint)", p0)); - ignored; - } - - function log(string memory p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string)", p0)); - ignored; - } - - function log(bool p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool)", p0)); - ignored; - } - - function log(address p0) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address)", p0)); - ignored; - } - - function log(uint p0, uint p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint)", p0, p1)); - ignored; - } - - function log(uint p0, string memory p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string)", p0, p1)); - ignored; - } - - function log(uint p0, bool p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool)", p0, p1)); - ignored; - } - - function log(uint p0, address p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address)", p0, p1)); - ignored; - } - - function log(string memory p0, uint p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint)", p0, p1)); - ignored; - } - - function log(string memory p0, string memory p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); - ignored; - } - - function log(string memory p0, bool p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool)", p0, p1)); - ignored; - } - - function log(string memory p0, address p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address)", p0, p1)); - ignored; - } - - function log(bool p0, uint p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint)", p0, p1)); - ignored; - } - - function log(bool p0, string memory p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string)", p0, p1)); - ignored; - } - - function log(bool p0, bool p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool)", p0, p1)); - ignored; - } - - function log(bool p0, address p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address)", p0, p1)); - ignored; - } - - function log(address p0, uint p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint)", p0, p1)); - ignored; - } - - function log(address p0, string memory p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string)", p0, p1)); - ignored; - } - - function log(address p0, bool p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool)", p0, p1)); - ignored; - } - - function log(address p0, address p1) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address)", p0, p1)); - ignored; - } - - function log(uint p0, uint p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); - ignored; - } - - function log(uint p0, uint p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); - ignored; - } - - function log(uint p0, uint p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); - ignored; - } - - function log(uint p0, uint p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); - ignored; - } - - function log(uint p0, string memory p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); - ignored; - } - - function log(uint p0, string memory p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); - ignored; - } - - function log(uint p0, string memory p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); - ignored; - } - - function log(uint p0, string memory p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); - ignored; - } - - function log(uint p0, bool p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); - ignored; - } - - function log(uint p0, bool p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); - ignored; - } - - function log(uint p0, bool p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); - ignored; - } - - function log(uint p0, bool p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); - ignored; - } - - function log(uint p0, address p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); - ignored; - } - - function log(uint p0, address p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); - ignored; - } - - function log(uint p0, address p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); - ignored; - } - - function log(uint p0, address p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, uint p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, uint p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, uint p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, uint p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, string memory p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, string memory p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, string memory p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, string memory p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, bool p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, bool p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, bool p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, bool p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, address p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, address p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, address p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); - ignored; - } - - function log(string memory p0, address p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); - ignored; - } - - function log(bool p0, uint p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); - ignored; - } - - function log(bool p0, uint p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); - ignored; - } - - function log(bool p0, uint p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); - ignored; - } - - function log(bool p0, uint p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); - ignored; - } - - function log(bool p0, string memory p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); - ignored; - } - - function log(bool p0, string memory p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); - ignored; - } - - function log(bool p0, string memory p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); - ignored; - } - - function log(bool p0, string memory p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); - ignored; - } - - function log(bool p0, bool p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); - ignored; - } - - function log(bool p0, bool p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); - ignored; - } - - function log(bool p0, bool p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); - ignored; - } - - function log(bool p0, bool p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); - ignored; - } - - function log(bool p0, address p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); - ignored; - } - - function log(bool p0, address p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); - ignored; - } - - function log(bool p0, address p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); - ignored; - } - - function log(bool p0, address p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); - ignored; - } - - function log(address p0, uint p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); - ignored; - } - - function log(address p0, uint p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); - ignored; - } - - function log(address p0, uint p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); - ignored; - } - - function log(address p0, uint p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); - ignored; - } - - function log(address p0, string memory p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); - ignored; - } - - function log(address p0, string memory p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); - ignored; - } - - function log(address p0, string memory p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); - ignored; - } - - function log(address p0, string memory p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); - ignored; - } - - function log(address p0, bool p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); - ignored; - } - - function log(address p0, bool p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); - ignored; - } - - function log(address p0, bool p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); - ignored; - } - - function log(address p0, bool p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); - ignored; - } - - function log(address p0, address p1, uint p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); - ignored; - } - - function log(address p0, address p1, string memory p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); - ignored; - } - - function log(address p0, address p1, bool p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); - ignored; - } - - function log(address p0, address p1, address p2) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); - ignored; - } - - function log(uint p0, uint p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, uint p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, string memory p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, bool p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(uint p0, address p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, uint p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, string memory p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, bool p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(string memory p0, address p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, uint p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, string memory p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, bool p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(bool p0, address p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, uint p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, string memory p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, bool p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, uint p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, uint p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, uint p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, uint p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, string memory p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, string memory p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, string memory p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, string memory p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, bool p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, bool p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, bool p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, bool p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, address p2, uint p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, address p2, string memory p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, address p2, bool p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); - ignored; - } - - function log(address p0, address p1, address p2, address p3) internal view { - (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); - ignored; - } - + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function log() internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log()")); + ignored; + } + + function logInt(int p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(int)", p0)); + ignored; + } + + function logUint(uint p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint)", p0)); + ignored; + } + + function logString(string memory p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string)", p0)); + ignored; + } + + function logBool(bool p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool)", p0)); + ignored; + } + + function logAddress(address p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address)", p0)); + ignored; + } + + function logBytes(bytes memory p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes)", p0)); + ignored; + } + + function logByte(bytes1 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(byte)", p0)); + ignored; + } + + function logBytes1(bytes1 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes1)", p0)); + ignored; + } + + function logBytes2(bytes2 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes2)", p0)); + ignored; + } + + function logBytes3(bytes3 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes3)", p0)); + ignored; + } + + function logBytes4(bytes4 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes4)", p0)); + ignored; + } + + function logBytes5(bytes5 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes5)", p0)); + ignored; + } + + function logBytes6(bytes6 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes6)", p0)); + ignored; + } + + function logBytes7(bytes7 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes7)", p0)); + ignored; + } + + function logBytes8(bytes8 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes8)", p0)); + ignored; + } + + function logBytes9(bytes9 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes9)", p0)); + ignored; + } + + function logBytes10(bytes10 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes10)", p0)); + ignored; + } + + function logBytes11(bytes11 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes11)", p0)); + ignored; + } + + function logBytes12(bytes12 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes12)", p0)); + ignored; + } + + function logBytes13(bytes13 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes13)", p0)); + ignored; + } + + function logBytes14(bytes14 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes14)", p0)); + ignored; + } + + function logBytes15(bytes15 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes15)", p0)); + ignored; + } + + function logBytes16(bytes16 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes16)", p0)); + ignored; + } + + function logBytes17(bytes17 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes17)", p0)); + ignored; + } + + function logBytes18(bytes18 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes18)", p0)); + ignored; + } + + function logBytes19(bytes19 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes19)", p0)); + ignored; + } + + function logBytes20(bytes20 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes20)", p0)); + ignored; + } + + function logBytes21(bytes21 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes21)", p0)); + ignored; + } + + function logBytes22(bytes22 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes22)", p0)); + ignored; + } + + function logBytes23(bytes23 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes23)", p0)); + ignored; + } + + function logBytes24(bytes24 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes24)", p0)); + ignored; + } + + function logBytes25(bytes25 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes25)", p0)); + ignored; + } + + function logBytes26(bytes26 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes26)", p0)); + ignored; + } + + function logBytes27(bytes27 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes27)", p0)); + ignored; + } + + function logBytes28(bytes28 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes28)", p0)); + ignored; + } + + function logBytes29(bytes29 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes29)", p0)); + ignored; + } + + function logBytes30(bytes30 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes30)", p0)); + ignored; + } + + function logBytes31(bytes31 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes31)", p0)); + ignored; + } + + function logBytes32(bytes32 p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bytes32)", p0)); + ignored; + } + + function log(uint p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(uint)", p0)); + ignored; + } + + function log(string memory p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(string)", p0)); + ignored; + } + + function log(bool p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(bool)", p0)); + ignored; + } + + function log(address p0) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature("log(address)", p0)); + ignored; + } + + function log(uint p0, uint p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint)", p0, p1) + ); + ignored; + } + + function log(uint p0, string memory p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string)", p0, p1) + ); + ignored; + } + + function log(uint p0, bool p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool)", p0, p1) + ); + ignored; + } + + function log(uint p0, address p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address)", p0, p1) + ); + ignored; + } + + function log(string memory p0, uint p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint)", p0, p1) + ); + ignored; + } + + function log(string memory p0, string memory p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string)", p0, p1) + ); + ignored; + } + + function log(string memory p0, bool p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool)", p0, p1) + ); + ignored; + } + + function log(string memory p0, address p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address)", p0, p1) + ); + ignored; + } + + function log(bool p0, uint p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint)", p0, p1) + ); + ignored; + } + + function log(bool p0, string memory p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string)", p0, p1) + ); + ignored; + } + + function log(bool p0, bool p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool)", p0, p1) + ); + ignored; + } + + function log(bool p0, address p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address)", p0, p1) + ); + ignored; + } + + function log(address p0, uint p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint)", p0, p1) + ); + ignored; + } + + function log(address p0, string memory p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string)", p0, p1) + ); + ignored; + } + + function log(address p0, bool p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool)", p0, p1) + ); + ignored; + } + + function log(address p0, address p1) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address)", p0, p1) + ); + ignored; + } + + function log(uint p0, uint p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, uint p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, uint p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, uint p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, string memory p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, string memory p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, string memory p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, string memory p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, bool p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, bool p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, bool p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, bool p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, address p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, address p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, address p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, address p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, uint p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, uint p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, uint p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, uint p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, string memory p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,string)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, string memory p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, string memory p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,address)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, bool p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, bool p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, bool p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, bool p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, address p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, address p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,string)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, address p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2) + ); + ignored; + } + + function log(string memory p0, address p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,address)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, uint p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, uint p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, uint p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, uint p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, string memory p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, string memory p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, string memory p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, string memory p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, bool p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, bool p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, bool p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, bool p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, address p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, address p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, address p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2) + ); + ignored; + } + + function log(bool p0, address p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, uint p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, uint p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, uint p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, uint p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, string memory p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, string memory p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,string)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, string memory p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, string memory p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,address)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, bool p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, bool p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, bool p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, bool p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, address p1, uint p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, address p1, string memory p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,string)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, address p1, bool p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2) + ); + ignored; + } + + function log(address p0, address p1, address p2) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,address)", p0, p1, p2) + ); + ignored; + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(uint p0, address p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log( + string memory p0, + string memory p1, + string memory p2, + string memory p3 + ) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(bool p0, address p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, uint p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, bool p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, uint p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, bool p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, address p2, uint p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, address p2, bool p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3) + ); + ignored; + } + + function log(address p0, address p1, address p2, address p3) internal view { + (bool ignored, ) = CONSOLE_ADDRESS.staticcall( + abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3) + ); + ignored; + } } diff --git a/contracts/Dependencies/permit2/AllowanceTransfer.sol b/contracts/Dependencies/permit2/AllowanceTransfer.sol index 876bc69..7f46fd8 100644 --- a/contracts/Dependencies/permit2/AllowanceTransfer.sol +++ b/contracts/Dependencies/permit2/AllowanceTransfer.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; -import {ERC20} from "./ERC20.sol"; -import {SafeTransferLib} from "./libraries/SafeTransferLib.sol"; -import {PermitHash} from "./libraries/PermitHash.sol"; -import {SignatureVerification} from "./libraries/SignatureVerification.sol"; -import {EIP712} from "./EIP712.sol"; -import {IAllowanceTransfer} from "./interfaces/IAllowanceTransfer.sol"; -import {SignatureExpired, InvalidNonce} from "./PermitErrors.sol"; -import {Allowance} from "./libraries/Allowance.sol"; +import { ERC20 } from "./ERC20.sol"; +import { SafeTransferLib } from "./libraries/SafeTransferLib.sol"; +import { PermitHash } from "./libraries/PermitHash.sol"; +import { SignatureVerification } from "./libraries/SignatureVerification.sol"; +import { EIP712 } from "./EIP712.sol"; +import { IAllowanceTransfer } from "./interfaces/IAllowanceTransfer.sol"; +import { SignatureExpired, InvalidNonce } from "./PermitErrors.sol"; +import { Allowance } from "./libraries/Allowance.sol"; contract AllowanceTransfer is IAllowanceTransfer, EIP712 { using SignatureVerification for bytes; @@ -30,8 +30,13 @@ contract AllowanceTransfer is IAllowanceTransfer, EIP712 { } /// @inheritdoc IAllowanceTransfer - function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external { - if (block.timestamp > permitSingle.sigDeadline) revert SignatureExpired(permitSingle.sigDeadline); + function permit( + address owner, + PermitSingle memory permitSingle, + bytes calldata signature + ) external { + if (block.timestamp > permitSingle.sigDeadline) + revert SignatureExpired(permitSingle.sigDeadline); // Verify the signer address from the signature. signature.verify(_hashTypedData(permitSingle.hash()), owner); @@ -40,8 +45,13 @@ contract AllowanceTransfer is IAllowanceTransfer, EIP712 { } /// @inheritdoc IAllowanceTransfer - function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external { - if (block.timestamp > permitBatch.sigDeadline) revert SignatureExpired(permitBatch.sigDeadline); + function permit( + address owner, + PermitBatch memory permitBatch, + bytes calldata signature + ) external { + if (block.timestamp > permitBatch.sigDeadline) + revert SignatureExpired(permitBatch.sigDeadline); // Verify the signer address from the signature. signature.verify(_hashTypedData(permitBatch.hash()), owner); @@ -66,7 +76,12 @@ contract AllowanceTransfer is IAllowanceTransfer, EIP712 { uint256 length = transferDetails.length; for (uint256 i = 0; i < length; ++i) { AllowanceTransferDetails memory transferDetail = transferDetails[i]; - _transfer(transferDetail.from, transferDetail.to, transferDetail.amount, transferDetail.token); + _transfer( + transferDetail.from, + transferDetail.to, + transferDetail.amount, + transferDetail.token + ); } } } @@ -128,7 +143,11 @@ contract AllowanceTransfer is IAllowanceTransfer, EIP712 { /// @notice Sets the new values for amount, expiration, and nonce. /// @dev Will check that the signed nonce is equal to the current nonce and then incrememnt the nonce value by 1. /// @dev Emits a Permit event. - function _updateApproval(PermitDetails memory details, address owner, address spender) private { + function _updateApproval( + PermitDetails memory details, + address owner, + address spender + ) private { uint48 nonce = details.nonce; address token = details.token; uint160 amount = details.amount; diff --git a/contracts/Dependencies/permit2/EIP712.sol b/contracts/Dependencies/permit2/EIP712.sol index 971a03d..de86e42 100644 --- a/contracts/Dependencies/permit2/EIP712.sol +++ b/contracts/Dependencies/permit2/EIP712.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; -import {IEIP712} from "./interfaces/IEIP712.sol"; +import { IEIP712 } from "./interfaces/IEIP712.sol"; /// @notice EIP712 helpers for permit2 /// @dev Maintains cross-chain replay protection in the event of a fork @@ -24,13 +24,17 @@ contract EIP712 is IEIP712 { /// @notice Returns the domain separator for the current chain. /// @dev Uses cached version if chainid and address are unchanged from construction. function DOMAIN_SEPARATOR() public view override returns (bytes32) { - return block.chainid == _CACHED_CHAIN_ID - ? _CACHED_DOMAIN_SEPARATOR - : _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME); + return + block.chainid == _CACHED_CHAIN_ID + ? _CACHED_DOMAIN_SEPARATOR + : _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME); } /// @notice Builds a domain separator using the current chainId and contract address. - function _buildDomainSeparator(bytes32 typeHash, bytes32 nameHash) private view returns (bytes32) { + function _buildDomainSeparator( + bytes32 typeHash, + bytes32 nameHash + ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, block.chainid, address(this))); } diff --git a/contracts/Dependencies/permit2/ERC20.sol b/contracts/Dependencies/permit2/ERC20.sol index 879f99e..f407204 100644 --- a/contracts/Dependencies/permit2/ERC20.sol +++ b/contracts/Dependencies/permit2/ERC20.sol @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; @@ -49,11 +48,7 @@ abstract contract ERC20 { CONSTRUCTOR //////////////////////////////////////////////////////////////*/ - constructor( - string memory _name, - string memory _symbol, - uint8 _decimals - ) { + constructor(string memory _name, string memory _symbol, uint8 _decimals) { name = _name; symbol = _symbol; decimals = _decimals; @@ -88,11 +83,7 @@ abstract contract ERC20 { return true; } - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual returns (bool) { + function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; @@ -161,14 +152,19 @@ abstract contract ERC20 { } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { - return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); + return + block.chainid == INITIAL_CHAIN_ID + ? INITIAL_DOMAIN_SEPARATOR + : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( - keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ), keccak256(bytes(name)), keccak256("1"), block.chainid, diff --git a/contracts/Dependencies/permit2/Permit2.sol b/contracts/Dependencies/permit2/Permit2.sol index 7249e40..cc7a623 100644 --- a/contracts/Dependencies/permit2/Permit2.sol +++ b/contracts/Dependencies/permit2/Permit2.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; -import {SignatureTransfer} from "./SignatureTransfer.sol"; -import {AllowanceTransfer} from "./AllowanceTransfer.sol"; +import { SignatureTransfer } from "./SignatureTransfer.sol"; +import { AllowanceTransfer } from "./AllowanceTransfer.sol"; /// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. /// @dev Users must approve Permit2 before calling any of the transfer functions. contract Permit2 is SignatureTransfer, AllowanceTransfer { -// Permit2 unifies the two contracts so users have maximal flexibility with their approval. + // Permit2 unifies the two contracts so users have maximal flexibility with their approval. } diff --git a/contracts/Dependencies/permit2/SignatureTransfer.sol b/contracts/Dependencies/permit2/SignatureTransfer.sol index 6494a9f..1c789f6 100644 --- a/contracts/Dependencies/permit2/SignatureTransfer.sol +++ b/contracts/Dependencies/permit2/SignatureTransfer.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; -import {ISignatureTransfer} from "./interfaces/ISignatureTransfer.sol"; -import {SignatureExpired, InvalidNonce} from "./PermitErrors.sol"; -import {ERC20} from "./ERC20.sol"; -import {SafeTransferLib} from "./libraries/SafeTransferLib.sol"; -import {SignatureVerification} from "./libraries/SignatureVerification.sol"; -import {PermitHash} from "./libraries/PermitHash.sol"; -import {EIP712} from "./EIP712.sol"; +import { ISignatureTransfer } from "./interfaces/ISignatureTransfer.sol"; +import { SignatureExpired, InvalidNonce } from "./PermitErrors.sol"; +import { ERC20 } from "./ERC20.sol"; +import { SafeTransferLib } from "./libraries/SafeTransferLib.sol"; +import { SignatureVerification } from "./libraries/SignatureVerification.sol"; +import { PermitHash } from "./libraries/PermitHash.sol"; +import { EIP712 } from "./EIP712.sol"; contract SignatureTransfer is ISignatureTransfer, EIP712 { using SignatureVerification for bytes; @@ -44,7 +44,8 @@ contract SignatureTransfer is ISignatureTransfer, EIP712 { uint256 requestedAmount = transferDetails.requestedAmount; if (block.timestamp > permit.deadline) revert SignatureExpired(permit.deadline); - if (requestedAmount > permit.permitted.amount) revert InvalidAmount(permit.permitted.amount); + if (requestedAmount > permit.permitted.amount) + revert InvalidAmount(permit.permitted.amount); _useUnorderedNonce(owner, permit.nonce); @@ -92,7 +93,11 @@ contract SignatureTransfer is ISignatureTransfer, EIP712 { if (requestedAmount != 0) { // allow spender to specify which of the permitted tokens should be transferred - ERC20(permitted.token).safeTransferFrom(owner, transferDetails[i].to, requestedAmount); + ERC20(permitted.token).safeTransferFrom( + owner, + transferDetails[i].to, + requestedAmount + ); } } } @@ -111,7 +116,9 @@ contract SignatureTransfer is ISignatureTransfer, EIP712 { /// @return bitPos The bit position /// @dev The first 248 bits of the nonce value is the index of the desired bitmap /// @dev The last 8 bits of the nonce value is the position of the bit in the bitmap - function bitmapPositions(uint256 nonce) private pure returns (uint256 wordPos, uint256 bitPos) { + function bitmapPositions( + uint256 nonce + ) private pure returns (uint256 wordPos, uint256 bitPos) { wordPos = uint248(nonce >> 8); bitPos = uint8(nonce); } diff --git a/contracts/Dependencies/permit2/interfaces/IAllowanceTransfer.sol b/contracts/Dependencies/permit2/interfaces/IAllowanceTransfer.sol index 712aa9d..c684b84 100644 --- a/contracts/Dependencies/permit2/interfaces/IAllowanceTransfer.sol +++ b/contracts/Dependencies/permit2/interfaces/IAllowanceTransfer.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IEIP712} from "./IEIP712.sol"; +import { IEIP712 } from "./IEIP712.sol"; /// @title AllowanceTransfer /// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts @@ -20,12 +20,20 @@ interface IAllowanceTransfer is IEIP712 { /// @notice Emits an event when the owner successfully invalidates an ordered nonce. event NonceInvalidation( - address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce + address indexed owner, + address indexed token, + address indexed spender, + uint48 newNonce, + uint48 oldNonce ); /// @notice Emits an event when the owner successfully sets permissions on a token for the spender. event Approval( - address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration + address indexed owner, + address indexed token, + address indexed spender, + uint160 amount, + uint48 expiration ); /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender. @@ -108,10 +116,11 @@ interface IAllowanceTransfer is IEIP712 { /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval. /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress] /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals. - function allowance(address user, address token, address spender) - external - view - returns (uint160 amount, uint48 expiration, uint48 nonce); + function allowance( + address user, + address token, + address spender + ) external view returns (uint160 amount, uint48 expiration, uint48 nonce); /// @notice Approves the spender to use up to amount of the specified token up until the expiration /// @param token The token to approve @@ -127,14 +136,22 @@ interface IAllowanceTransfer is IEIP712 { /// @param owner The owner of the tokens being approved /// @param permitSingle Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data - function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external; + function permit( + address owner, + PermitSingle memory permitSingle, + bytes calldata signature + ) external; /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce /// @param owner The owner of the tokens being approved /// @param permitBatch Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data - function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external; + function permit( + address owner, + PermitBatch memory permitBatch, + bytes calldata signature + ) external; /// @notice Transfer approved tokens from one address to another /// @param from The address to transfer from diff --git a/contracts/Dependencies/permit2/interfaces/IERC1271.sol b/contracts/Dependencies/permit2/interfaces/IERC1271.sol index a3c1cba..488dde2 100644 --- a/contracts/Dependencies/permit2/interfaces/IERC1271.sol +++ b/contracts/Dependencies/permit2/interfaces/IERC1271.sol @@ -6,5 +6,8 @@ interface IERC1271 { /// @param hash Hash of the data to be signed /// @param signature Signature byte array associated with _data /// @return magicValue The bytes4 magic value 0x1626ba7e - function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); + function isValidSignature( + bytes32 hash, + bytes memory signature + ) external view returns (bytes4 magicValue); } diff --git a/contracts/Dependencies/permit2/interfaces/IPermit2.sol b/contracts/Dependencies/permit2/interfaces/IPermit2.sol index a800a18..a668b91 100644 --- a/contracts/Dependencies/permit2/interfaces/IPermit2.sol +++ b/contracts/Dependencies/permit2/interfaces/IPermit2.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ISignatureTransfer} from "./ISignatureTransfer.sol"; -import {IAllowanceTransfer} from "./IAllowanceTransfer.sol"; +import { ISignatureTransfer } from "./ISignatureTransfer.sol"; +import { IAllowanceTransfer } from "./IAllowanceTransfer.sol"; /// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. /// @dev Users must approve Permit2 before calling any of the transfer functions. interface IPermit2 is ISignatureTransfer, IAllowanceTransfer { -// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. + // IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. } diff --git a/contracts/Dependencies/permit2/interfaces/ISignatureTransfer.sol b/contracts/Dependencies/permit2/interfaces/ISignatureTransfer.sol index 57459da..a69bd84 100644 --- a/contracts/Dependencies/permit2/interfaces/ISignatureTransfer.sol +++ b/contracts/Dependencies/permit2/interfaces/ISignatureTransfer.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IEIP712} from "./IEIP712.sol"; +import { IEIP712 } from "./IEIP712.sol"; /// @title SignatureTransfer /// @notice Handles ERC20 token transfers through signature based actions diff --git a/contracts/Dependencies/permit2/libraries/Allowance.sol b/contracts/Dependencies/permit2/libraries/Allowance.sol index 671c972..6c9fa45 100644 --- a/contracts/Dependencies/permit2/libraries/Allowance.sol +++ b/contracts/Dependencies/permit2/libraries/Allowance.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol"; +import { IAllowanceTransfer } from "../interfaces/IAllowanceTransfer.sol"; library Allowance { // note if the expiration passed is 0, then it the approval set to the block.timestamp @@ -21,7 +21,9 @@ library Allowance { storedNonce = nonce + 1; } - uint48 storedExpiration = expiration == BLOCK_TIMESTAMP_EXPIRATION ? uint48(block.timestamp) : expiration; + uint48 storedExpiration = expiration == BLOCK_TIMESTAMP_EXPIRATION + ? uint48(block.timestamp) + : expiration; uint256 word = pack(amount, storedExpiration, storedNonce); assembly { @@ -42,7 +44,11 @@ library Allowance { } /// @notice Computes the packed slot of the amount, expiration, and nonce that make up PackedAllowance - function pack(uint160 amount, uint48 expiration, uint48 nonce) internal pure returns (uint256 word) { - word = (uint256(nonce) << 208) | uint256(expiration) << 160 | amount; + function pack( + uint160 amount, + uint48 expiration, + uint48 nonce + ) internal pure returns (uint256 word) { + word = (uint256(nonce) << 208) | (uint256(expiration) << 160) | amount; } } diff --git a/contracts/Dependencies/permit2/libraries/Permit2Lib.sol b/contracts/Dependencies/permit2/libraries/Permit2Lib.sol index 3901342..843b57a 100644 --- a/contracts/Dependencies/permit2/libraries/Permit2Lib.sol +++ b/contracts/Dependencies/permit2/libraries/Permit2Lib.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {ERC20} from "../ERC20.sol"; +import { ERC20 } from "../ERC20.sol"; -import {IDAIPermit} from "../interfaces/IDAIPermit.sol"; -import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol"; -import {SafeCast160} from "./SafeCast160.sol"; +import { IDAIPermit } from "../interfaces/IDAIPermit.sol"; +import { IAllowanceTransfer } from "../interfaces/IAllowanceTransfer.sol"; +import { SafeCast160 } from "./SafeCast160.sol"; /// @title Permit2Lib /// @notice Enables efficient transfers and EIP-2612/DAI @@ -17,10 +17,12 @@ library Permit2Lib { //////////////////////////////////////////////////////////////*/ /// @dev The unique EIP-712 domain domain separator for the DAI token contract. - bytes32 internal constant DAI_DOMAIN_SEPARATOR = 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7; + bytes32 internal constant DAI_DOMAIN_SEPARATOR = + 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7; /// @dev The address for the WETH9 contract on Ethereum mainnet, encoded as a bytes32. - bytes32 internal constant WETH9_ADDRESS = 0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2; + bytes32 internal constant WETH9_ADDRESS = + 0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2; /// @dev The address of the Permit2 contract the library will use. IAllowanceTransfer internal constant PERMIT2 = @@ -37,16 +39,15 @@ library Permit2Lib { bool success; // Call the token contract as normal, capturing whether it succeeded. assembly { - success := - and( - // Set success to whether the call reverted, if not we check it either - // returned exactly 1 (can't just be non-zero data), or had no return data. - or(eq(mload(0), 1), iszero(returndatasize())), - // Counterintuitively, this call() must be positioned after the or() in the - // surrounding and() because and() evaluates its arguments from right to left. - // We use 0 and 32 to copy up to 32 bytes of return data into the first slot of scratch space. - call(gas(), token, 0, add(inputData, 32), mload(inputData), 0, 32) - ) + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(eq(mload(0), 1), iszero(returndatasize())), + // Counterintuitively, this call() must be positioned after the or() in the + // surrounding and() because and() evaluates its arguments from right to left. + // We use 0 and 32 to copy up to 32 bytes of return data into the first slot of scratch space. + call(gas(), token, 0, add(inputData, 32), mload(inputData), 0, 32) + ) } // We'll fall back to using Permit2 if calling transferFrom on the token directly reverted. @@ -88,17 +89,16 @@ library Permit2Lib { // If the token is WETH9, we know it doesn't have a DOMAIN_SEPARATOR, and we'll skip this step. // We make sure to mask the token address as its higher order bits aren't guaranteed to be clean. if iszero(eq(and(token, 0xffffffffffffffffffffffffffffffffffffffff), WETH9_ADDRESS)) { - success := - and( - // Should resolve false if its not 32 bytes or its first word is 0. - and(iszero(iszero(mload(0))), eq(returndatasize(), 32)), - // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. - // Counterintuitively, this call must be positioned second to the and() call in the - // surrounding and() call or else returndatasize() will be zero during the computation. - // We send a maximum of 5000 gas to prevent tokens with fallbacks from using a ton of gas. - // which should be plenty to allow tokens to fetch their DOMAIN_SEPARATOR from storage, etc. - staticcall(5000, token, add(inputData, 32), mload(inputData), 0, 32) - ) + success := and( + // Should resolve false if its not 32 bytes or its first word is 0. + and(iszero(iszero(mload(0))), eq(returndatasize(), 32)), + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the and() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + // We send a maximum of 5000 gas to prevent tokens with fallbacks from using a ton of gas. + // which should be plenty to allow tokens to fetch their DOMAIN_SEPARATOR from storage, etc. + staticcall(5000, token, add(inputData, 32), mload(inputData), 0, 32) + ) domainSeparator := mload(0) // Copy the return value into the domainSeparator variable. } @@ -109,7 +109,10 @@ library Permit2Lib { // We'll use DAI's special permit if it's DOMAIN_SEPARATOR matches, // otherwise we'll just encode a call to the standard permit function. inputData = domainSeparator == DAI_DOMAIN_SEPARATOR - ? abi.encodeCall(IDAIPermit.permit, (owner, spender, token.nonces(owner), deadline, true, v, r, s)) + ? abi.encodeCall( + IDAIPermit.permit, + (owner, spender, token.nonces(owner), deadline, true, v, r, s) + ) : abi.encodeCall(ERC20.permit, (owner, spender, amount, deadline, v, r, s)); assembly { @@ -143,7 +146,7 @@ library Permit2Lib { bytes32 r, bytes32 s ) internal { - (,, uint48 nonce) = PERMIT2.allowance(owner, address(token), spender); + (, , uint48 nonce) = PERMIT2.allowance(owner, address(token), spender); PERMIT2.permit( owner, diff --git a/contracts/Dependencies/permit2/libraries/PermitHash.sol b/contracts/Dependencies/permit2/libraries/PermitHash.sol index 32d4a83..4f1f0f8 100644 --- a/contracts/Dependencies/permit2/libraries/PermitHash.sol +++ b/contracts/Dependencies/permit2/libraries/PermitHash.sol @@ -1,32 +1,38 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol"; -import {ISignatureTransfer} from "../interfaces/ISignatureTransfer.sol"; +import { IAllowanceTransfer } from "../interfaces/IAllowanceTransfer.sol"; +import { ISignatureTransfer } from "../interfaces/ISignatureTransfer.sol"; library PermitHash { bytes32 public constant _PERMIT_DETAILS_TYPEHASH = keccak256("PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"); - bytes32 public constant _PERMIT_SINGLE_TYPEHASH = keccak256( - "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" - ); + bytes32 public constant _PERMIT_SINGLE_TYPEHASH = + keccak256( + "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" + ); - bytes32 public constant _PERMIT_BATCH_TYPEHASH = keccak256( - "PermitBatch(PermitDetails[] details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" - ); + bytes32 public constant _PERMIT_BATCH_TYPEHASH = + keccak256( + "PermitBatch(PermitDetails[] details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)" + ); - bytes32 public constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256("TokenPermissions(address token,uint256 amount)"); + bytes32 public constant _TOKEN_PERMISSIONS_TYPEHASH = + keccak256("TokenPermissions(address token,uint256 amount)"); - bytes32 public constant _PERMIT_TRANSFER_FROM_TYPEHASH = keccak256( - "PermitTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)" - ); + bytes32 public constant _PERMIT_TRANSFER_FROM_TYPEHASH = + keccak256( + "PermitTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)" + ); - bytes32 public constant _PERMIT_BATCH_TRANSFER_FROM_TYPEHASH = keccak256( - "PermitBatchTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)" - ); + bytes32 public constant _PERMIT_BATCH_TRANSFER_FROM_TYPEHASH = + keccak256( + "PermitBatchTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)" + ); - string public constant _TOKEN_PERMISSIONS_TYPESTRING = "TokenPermissions(address token,uint256 amount)"; + string public constant _TOKEN_PERMISSIONS_TYPESTRING = + "TokenPermissions(address token,uint256 amount)"; string public constant _PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB = "PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,"; @@ -34,36 +40,59 @@ library PermitHash { string public constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB = "PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,"; - function hash(IAllowanceTransfer.PermitSingle memory permitSingle) internal pure returns (bytes32) { + function hash( + IAllowanceTransfer.PermitSingle memory permitSingle + ) internal pure returns (bytes32) { bytes32 permitHash = _hashPermitDetails(permitSingle.details); return - keccak256(abi.encode(_PERMIT_SINGLE_TYPEHASH, permitHash, permitSingle.spender, permitSingle.sigDeadline)); + keccak256( + abi.encode( + _PERMIT_SINGLE_TYPEHASH, + permitHash, + permitSingle.spender, + permitSingle.sigDeadline + ) + ); } - function hash(IAllowanceTransfer.PermitBatch memory permitBatch) internal pure returns (bytes32) { + function hash( + IAllowanceTransfer.PermitBatch memory permitBatch + ) internal pure returns (bytes32) { uint256 numPermits = permitBatch.details.length; bytes32[] memory permitHashes = new bytes32[](numPermits); for (uint256 i = 0; i < numPermits; ++i) { permitHashes[i] = _hashPermitDetails(permitBatch.details[i]); } - return keccak256( - abi.encode( - _PERMIT_BATCH_TYPEHASH, - keccak256(abi.encodePacked(permitHashes)), - permitBatch.spender, - permitBatch.sigDeadline - ) - ); + return + keccak256( + abi.encode( + _PERMIT_BATCH_TYPEHASH, + keccak256(abi.encodePacked(permitHashes)), + permitBatch.spender, + permitBatch.sigDeadline + ) + ); } - function hash(ISignatureTransfer.PermitTransferFrom memory permit) internal view returns (bytes32) { + function hash( + ISignatureTransfer.PermitTransferFrom memory permit + ) internal view returns (bytes32) { bytes32 tokenPermissionsHash = _hashTokenPermissions(permit.permitted); - return keccak256( - abi.encode(_PERMIT_TRANSFER_FROM_TYPEHASH, tokenPermissionsHash, msg.sender, permit.nonce, permit.deadline) - ); + return + keccak256( + abi.encode( + _PERMIT_TRANSFER_FROM_TYPEHASH, + tokenPermissionsHash, + msg.sender, + permit.nonce, + permit.deadline + ) + ); } - function hash(ISignatureTransfer.PermitBatchTransferFrom memory permit) internal view returns (bytes32) { + function hash( + ISignatureTransfer.PermitBatchTransferFrom memory permit + ) internal view returns (bytes32) { uint256 numPermitted = permit.permitted.length; bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted); @@ -71,15 +100,16 @@ library PermitHash { tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]); } - return keccak256( - abi.encode( - _PERMIT_BATCH_TRANSFER_FROM_TYPEHASH, - keccak256(abi.encodePacked(tokenPermissionHashes)), - msg.sender, - permit.nonce, - permit.deadline - ) - ); + return + keccak256( + abi.encode( + _PERMIT_BATCH_TRANSFER_FROM_TYPEHASH, + keccak256(abi.encodePacked(tokenPermissionHashes)), + msg.sender, + permit.nonce, + permit.deadline + ) + ); } function hashWithWitness( @@ -87,10 +117,22 @@ library PermitHash { bytes32 witness, string calldata witnessTypeString ) internal view returns (bytes32) { - bytes32 typeHash = keccak256(abi.encodePacked(_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, witnessTypeString)); + bytes32 typeHash = keccak256( + abi.encodePacked(_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, witnessTypeString) + ); bytes32 tokenPermissionsHash = _hashTokenPermissions(permit.permitted); - return keccak256(abi.encode(typeHash, tokenPermissionsHash, msg.sender, permit.nonce, permit.deadline, witness)); + return + keccak256( + abi.encode( + typeHash, + tokenPermissionsHash, + msg.sender, + permit.nonce, + permit.deadline, + witness + ) + ); } function hashWithWitness( @@ -98,8 +140,9 @@ library PermitHash { bytes32 witness, string calldata witnessTypeString ) internal view returns (bytes32) { - bytes32 typeHash = - keccak256(abi.encodePacked(_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString)); + bytes32 typeHash = keccak256( + abi.encodePacked(_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString) + ); uint256 numPermitted = permit.permitted.length; bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted); @@ -108,27 +151,28 @@ library PermitHash { tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]); } - return keccak256( - abi.encode( - typeHash, - keccak256(abi.encodePacked(tokenPermissionHashes)), - msg.sender, - permit.nonce, - permit.deadline, - witness - ) - ); + return + keccak256( + abi.encode( + typeHash, + keccak256(abi.encodePacked(tokenPermissionHashes)), + msg.sender, + permit.nonce, + permit.deadline, + witness + ) + ); } - function _hashPermitDetails(IAllowanceTransfer.PermitDetails memory details) private pure returns (bytes32) { + function _hashPermitDetails( + IAllowanceTransfer.PermitDetails memory details + ) private pure returns (bytes32) { return keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, details)); } - function _hashTokenPermissions(ISignatureTransfer.TokenPermissions memory permitted) - private - pure - returns (bytes32) - { + function _hashTokenPermissions( + ISignatureTransfer.TokenPermissions memory permitted + ) private pure returns (bytes32) { return keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permitted)); } } diff --git a/contracts/Dependencies/permit2/libraries/SafeTransferLib.sol b/contracts/Dependencies/permit2/libraries/SafeTransferLib.sol index 19b2760..f62576f 100644 --- a/contracts/Dependencies/permit2/libraries/SafeTransferLib.sol +++ b/contracts/Dependencies/permit2/libraries/SafeTransferLib.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; -import {ERC20} from "../ERC20.sol"; +import { ERC20 } from "../ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) @@ -28,12 +28,7 @@ library SafeTransferLib { ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ - function safeTransferFrom( - ERC20 token, - address from, - address to, - uint256 amount - ) internal { + function safeTransferFrom(ERC20 token, address from, address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly @@ -42,7 +37,10 @@ library SafeTransferLib { let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. - mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) + mstore( + freeMemoryPointer, + 0x23b872dd00000000000000000000000000000000000000000000000000000000 + ) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. @@ -62,11 +60,7 @@ library SafeTransferLib { require(success, "TRANSFER_FROM_FAILED"); } - function safeTransfer( - ERC20 token, - address to, - uint256 amount - ) internal { + function safeTransfer(ERC20 token, address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly @@ -75,7 +69,10 @@ library SafeTransferLib { let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. - mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) + mstore( + freeMemoryPointer, + 0xa9059cbb00000000000000000000000000000000000000000000000000000000 + ) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. @@ -94,11 +91,7 @@ library SafeTransferLib { require(success, "TRANSFER_FAILED"); } - function safeApprove( - ERC20 token, - address to, - uint256 amount - ) internal { + function safeApprove(ERC20 token, address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly @@ -107,7 +100,10 @@ library SafeTransferLib { let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. - mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) + mstore( + freeMemoryPointer, + 0x095ea7b300000000000000000000000000000000000000000000000000000000 + ) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. diff --git a/contracts/Dependencies/permit2/libraries/SignatureVerification.sol b/contracts/Dependencies/permit2/libraries/SignatureVerification.sol index 904dfcd..2fabfbb 100644 --- a/contracts/Dependencies/permit2/libraries/SignatureVerification.sol +++ b/contracts/Dependencies/permit2/libraries/SignatureVerification.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {IERC1271} from "../interfaces/IERC1271.sol"; +import { IERC1271 } from "../interfaces/IERC1271.sol"; library SignatureVerification { /// @notice Thrown when the passed in signature is not a valid length @@ -16,7 +16,9 @@ library SignatureVerification { /// @notice Thrown when the recovered contract signature is incorrect error InvalidContractSignature(); - bytes32 constant UPPER_BIT_MASK = (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + bytes32 constant UPPER_BIT_MASK = ( + 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ); function verify(bytes calldata signature, bytes32 hash, address claimedSigner) internal view { bytes32 r; @@ -41,7 +43,8 @@ library SignatureVerification { if (signer != claimedSigner) revert InvalidSigner(); } else { bytes4 magicValue = IERC1271(claimedSigner).isValidSignature(hash, signature); - if (magicValue != IERC1271.isValidSignature.selector) revert InvalidContractSignature(); + if (magicValue != IERC1271.isValidSignature.selector) + revert InvalidContractSignature(); } } } diff --git a/contracts/HintHelpers.sol b/contracts/HintHelpers.sol index 3f77c3a..37ada45 100644 --- a/contracts/HintHelpers.sol +++ b/contracts/HintHelpers.sol @@ -136,15 +136,7 @@ contract HintHelpers is LiquityBase, HintHelpersStorage, CheckContract { uint256 _CR, uint256 _numTrials, uint256 _inputRandomSeed - ) - external - view - returns ( - address hintAddress, - uint256 diff, - uint256 latestRandomSeed - ) - { + ) external view returns (address hintAddress, uint256 diff, uint256 latestRandomSeed) { uint256 arrayLength = troveManager.getTroveOwnersCount(); if (arrayLength == 0) { diff --git a/contracts/Interfaces/IAllowanceTransfer.sol b/contracts/Interfaces/IAllowanceTransfer.sol index 8f4b339..6959348 100644 --- a/contracts/Interfaces/IAllowanceTransfer.sol +++ b/contracts/Interfaces/IAllowanceTransfer.sol @@ -2,7 +2,7 @@ pragma solidity 0.6.11; pragma experimental ABIEncoderV2; -import {IEIP712} from "./IEIP712.sol"; +import { IEIP712 } from "./IEIP712.sol"; /// @title AllowanceTransfer /// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts @@ -10,12 +10,20 @@ import {IEIP712} from "./IEIP712.sol"; interface IAllowanceTransfer is IEIP712 { /// @notice Emits an event when the owner successfully invalidates an ordered nonce. event NonceInvalidation( - address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce + address indexed owner, + address indexed token, + address indexed spender, + uint48 newNonce, + uint48 oldNonce ); /// @notice Emits an event when the owner successfully sets permissions on a token for the spender. event Approval( - address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration + address indexed owner, + address indexed token, + address indexed spender, + uint160 amount, + uint48 expiration ); /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender. @@ -98,10 +106,11 @@ interface IAllowanceTransfer is IEIP712 { /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval. /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress] /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals. - function allowance(address user, address token, address spender) - external - view - returns (uint160 amount, uint48 expiration, uint48 nonce); + function allowance( + address user, + address token, + address spender + ) external view returns (uint160 amount, uint48 expiration, uint48 nonce); /// @notice Approves the spender to use up to amount of the specified token up until the expiration /// @param token The token to approve @@ -117,14 +126,22 @@ interface IAllowanceTransfer is IEIP712 { /// @param owner The owner of the tokens being approved /// @param permitSingle Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data - function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external; + function permit( + address owner, + PermitSingle memory permitSingle, + bytes calldata signature + ) external; /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce /// @param owner The owner of the tokens being approved /// @param permitBatch Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data - function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external; + function permit( + address owner, + PermitBatch memory permitBatch, + bytes calldata signature + ) external; /// @notice Transfer approved tokens from one address to another /// @param from The address to transfer from diff --git a/contracts/Interfaces/IBalanceRedirectPresale.sol b/contracts/Interfaces/IBalanceRedirectPresale.sol index e651fd4..4a3e192 100644 --- a/contracts/Interfaces/IBalanceRedirectPresale.sol +++ b/contracts/Interfaces/IBalanceRedirectPresale.sol @@ -3,6 +3,5 @@ pragma solidity 0.6.11; interface IBalanceRedirectPresale { - - function isClosed() external view returns (bool); -} \ No newline at end of file + function isClosed() external view returns (bool); +} diff --git a/contracts/Interfaces/IBorrowerOperations.sol b/contracts/Interfaces/IBorrowerOperations.sol index d6ed054..8b0a78f 100644 --- a/contracts/Interfaces/IBorrowerOperations.sol +++ b/contracts/Interfaces/IBorrowerOperations.sol @@ -190,7 +190,10 @@ interface IBorrowerOperations { * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD. */ - function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external; + function closeNueTroveWithPermit2( + ISignatureTransfer.PermitTransferFrom memory _permit, + bytes calldata _signature + ) external; /** * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity: diff --git a/contracts/Interfaces/ICollSurplusPool.sol b/contracts/Interfaces/ICollSurplusPool.sol index 03b9901..a1b8013 100644 --- a/contracts/Interfaces/ICollSurplusPool.sol +++ b/contracts/Interfaces/ICollSurplusPool.sol @@ -57,4 +57,26 @@ interface ICollSurplusPool { address _feeReceiver, uint256 _feeAmount ) external returns (bool feePaid); + + /// @notice Two-leg claim that pays the remainder to `_netRecipient` instead of + /// to `_account`. Only callable by BorrowerOperations. The claim is + /// still resolved against `_account`'s balance and the account keeps + /// its claim: the recipient only names where the net leg is sent, so + /// the perimeter can escrow it in the exit delay queue. Passing + /// `_account` as the recipient is exactly `claimCollWithFee`. + /// A zero `_feeAmount` skips the fee leg entirely rather than making + /// a zero-value call, so an uncharged-but-delayed claim does not + /// report a fee that was never taken. + /// @param _account account whose claimable collateral is paid out + /// @param _feeReceiver Perimeter fee destination for the fee leg + /// @param _feeAmount fee in wei; must not exceed the account's claimable balance + /// @param _netRecipient destination of the remainder after the fee leg + /// @return feePaid true iff a fee leg ran and succeeded + /// @return netAmount wei actually sent to `_netRecipient` + function claimCollWithFeeTo( + address _account, + address _feeReceiver, + uint256 _feeAmount, + address _netRecipient + ) external returns (bool feePaid, uint256 netAmount); } diff --git a/contracts/Interfaces/ICommunityIssuance.sol b/contracts/Interfaces/ICommunityIssuance.sol index 87d5197..fd3ac7e 100644 --- a/contracts/Interfaces/ICommunityIssuance.sol +++ b/contracts/Interfaces/ICommunityIssuance.sol @@ -2,10 +2,9 @@ pragma solidity 0.6.11; -interface ICommunityIssuance { - +interface ICommunityIssuance { // --- Events --- - + event SOVTokenAddressSet(address _zeroTokenAddress); event ZUSDTokenAddressSet(address _zusdTokenAddress); event StabilityPoolAddressSet(address _stabilityPoolAddress); @@ -54,7 +53,7 @@ interface ICommunityIssuance { function setRewardManager(address _rewardManagerAddress) external; /// @notice issues SOV tokens based on total zusd is deposited. - /// @return SOV tokens issuance + /// @return SOV tokens issuance function issueSOV(uint256 _totalZUSDDeposits) external returns (uint256); /// @notice sends ZERO tokens to given account diff --git a/contracts/Interfaces/IFeeSharingCollector.sol b/contracts/Interfaces/IFeeSharingCollector.sol index 1842650..4fd06c8 100644 --- a/contracts/Interfaces/IFeeSharingCollector.sol +++ b/contracts/Interfaces/IFeeSharingCollector.sol @@ -6,15 +6,11 @@ pragma solidity 0.6.11; * @dev Interfaces are used to cast a contract address into a callable instance. * */ interface IFeeSharingCollector { - function withdrawFees(address _token) external; + function withdrawFees(address _token) external; - function transferTokens(address _token, uint96 _amount) external; + function transferTokens(address _token, uint96 _amount) external; - function withdraw( - address _loanPoolToken, - uint32 _maxCheckpoints, - address _receiver - ) external; + function withdraw(address _loanPoolToken, uint32 _maxCheckpoints, address _receiver) external; - function transferRBTC() external payable; + function transferRBTC() external payable; } diff --git a/contracts/Interfaces/ILiquityBaseParams.sol b/contracts/Interfaces/ILiquityBaseParams.sol index 791711e..c8fca17 100644 --- a/contracts/Interfaces/ILiquityBaseParams.sol +++ b/contracts/Interfaces/ILiquityBaseParams.sol @@ -3,7 +3,6 @@ pragma solidity 0.6.11; interface ILiquityBaseParams { - /// Minimum collateral ratio for individual troves function MCR() external view returns (uint); @@ -21,5 +20,4 @@ interface ILiquityBaseParams { function REDEMPTION_FEE_FLOOR() external view returns (uint); function MAX_BORROWING_FEE() external view returns (uint); - -} \ No newline at end of file +} diff --git a/contracts/Interfaces/IPermit2.sol b/contracts/Interfaces/IPermit2.sol index f21ce7e..f1814bd 100644 --- a/contracts/Interfaces/IPermit2.sol +++ b/contracts/Interfaces/IPermit2.sol @@ -2,11 +2,11 @@ pragma solidity 0.6.11; pragma experimental ABIEncoderV2; -import {ISignatureTransfer} from "./ISignatureTransfer.sol"; -import {IAllowanceTransfer} from "./IAllowanceTransfer.sol"; +import { ISignatureTransfer } from "./ISignatureTransfer.sol"; +import { IAllowanceTransfer } from "./IAllowanceTransfer.sol"; /// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. /// @dev Users must approve Permit2 before calling any of the transfer functions. interface IPermit2 is ISignatureTransfer, IAllowanceTransfer { -// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. + // IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. } diff --git a/contracts/Interfaces/IPriceFeedSovryn.sol b/contracts/Interfaces/IPriceFeedSovryn.sol index 0a0e07b..e3287a8 100644 --- a/contracts/Interfaces/IPriceFeedSovryn.sol +++ b/contracts/Interfaces/IPriceFeedSovryn.sol @@ -13,15 +13,15 @@ pragma solidity 0.6.11; * drawdown, margin and collateral. * */ interface IPriceFeedSovryn { - function queryRate(address sourceToken, address destToken) - external - view - returns (uint256 rate, uint256 precision); + function queryRate( + address sourceToken, + address destToken + ) external view returns (uint256 rate, uint256 precision); - function queryPrecision(address sourceToken, address destToken) - external - view - returns (uint256 precision); + function queryPrecision( + address sourceToken, + address destToken + ) external view returns (uint256 precision); function queryReturn( address sourceToken, diff --git a/contracts/Interfaces/ISignatureTransfer.sol b/contracts/Interfaces/ISignatureTransfer.sol index 6038f55..467582d 100644 --- a/contracts/Interfaces/ISignatureTransfer.sol +++ b/contracts/Interfaces/ISignatureTransfer.sol @@ -2,7 +2,7 @@ pragma solidity 0.6.11; pragma experimental ABIEncoderV2; -import {IEIP712} from "./IEIP712.sol"; +import { IEIP712 } from "./IEIP712.sol"; /// @title SignatureTransfer /// @notice Handles ERC20 token transfers through signature based actions diff --git a/contracts/Interfaces/ISortedTroves.sol b/contracts/Interfaces/ISortedTroves.sol index b0e2f7d..6023624 100644 --- a/contracts/Interfaces/ISortedTroves.sol +++ b/contracts/Interfaces/ISortedTroves.sol @@ -33,12 +33,7 @@ interface ISortedTroves { * @param _prevId Id of previous node for the insert position * @param _nextId Id of next node for the insert position */ - function insert( - address _id, - uint256 _ICR, - address _prevId, - address _nextId - ) external; + function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external; /** * @dev Remove a node from the list @@ -53,12 +48,7 @@ interface ISortedTroves { * @param _prevId Id of previous node for the new insert position * @param _nextId Id of next node for the new insert position */ - function reInsert( - address _id, - uint256 _newICR, - address _prevId, - address _nextId - ) external; + function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external; /** * @dev Checks if the list contains a node diff --git a/contracts/Interfaces/ITroveManager.sol b/contracts/Interfaces/ITroveManager.sol index bb0c442..e6c3d09 100644 --- a/contracts/Interfaces/ITroveManager.sol +++ b/contracts/Interfaces/ITroveManager.sol @@ -199,7 +199,6 @@ interface ITroveManager is ILiquityBase { ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature ) external; - /// @notice Update borrower's stake based on their latest collateral value /// @param _borrower borrower address diff --git a/contracts/Interfaces/IWrbtc.sol b/contracts/Interfaces/IWrbtc.sol index efd7b9c..4afb31c 100644 --- a/contracts/Interfaces/IWrbtc.sol +++ b/contracts/Interfaces/IWrbtc.sol @@ -4,9 +4,7 @@ pragma solidity 0.6.11; import "../Dependencies/IERC20.sol"; interface IWrbtc is IERC20 { - - function deposit() external payable; - - function withdraw(uint256 wad) external; + function deposit() external payable; + function withdraw(uint256 wad) external; } diff --git a/contracts/Interfaces/IZEROToken.sol b/contracts/Interfaces/IZEROToken.sol index e6c0df9..9e308eb 100644 --- a/contracts/Interfaces/IZEROToken.sol +++ b/contracts/Interfaces/IZEROToken.sol @@ -5,8 +5,7 @@ pragma solidity 0.6.11; import "../Dependencies/IERC20.sol"; import "../Dependencies/IERC2612.sol"; -interface IZEROToken is IERC20, IERC2612 { - +interface IZEROToken is IERC20, IERC2612 { // --- Functions --- /// @notice send zero tokens to ZEROStaking contract @@ -16,5 +15,4 @@ interface IZEROToken is IERC20, IERC2612 { /// @return deployment start time function getDeploymentStartTime() external view returns (uint256); - } diff --git a/contracts/Interfaces/IZUSDToken.sol b/contracts/Interfaces/IZUSDToken.sol index 35b4f03..6b74d4e 100644 --- a/contracts/Interfaces/IZUSDToken.sol +++ b/contracts/Interfaces/IZUSDToken.sol @@ -5,8 +5,7 @@ pragma solidity 0.6.11; import "../Dependencies/IERC20.sol"; import "../Dependencies/IERC2612.sol"; -interface IZUSDToken is IERC20, IERC2612 { - +interface IZUSDToken is IERC20, IERC2612 { // --- Events --- event TroveManagerAddressChanged(address _troveManagerAddress); @@ -21,7 +20,7 @@ interface IZUSDToken is IERC20, IERC2612 { function burn(address _account, uint256 _amount) external; - function sendToPool(address _sender, address poolAddress, uint256 _amount) external; + function sendToPool(address _sender, address poolAddress, uint256 _amount) external; - function returnFromPool(address poolAddress, address user, uint256 _amount ) external; + function returnFromPool(address poolAddress, address user, uint256 _amount) external; } diff --git a/contracts/Interfaces/perimeter/IExitDelayQueue.sol b/contracts/Interfaces/perimeter/IExitDelayQueue.sol new file mode 100644 index 0000000..1a464db --- /dev/null +++ b/contracts/Interfaces/perimeter/IExitDelayQueue.sol @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: MIT +// ───────────────────────────────────────────────────────────────────────────── +// PROVENANCE — copied verbatim from DistributedCollective/perimeter +// @ 51457b21bc9a87958e99ea51325ded150422e791 +// src/interfaces/IExitDelayQueue.sol +// Do NOT modify the ABI here — the queue's IExitDelayQueue is final. +// To update: change upstream, re-copy, bump the SHA in this header. +// +// This file is the authoritative type/event/error + ABI catalog, kept for ABI +// parity and off-chain tooling. Upstream pins `0.8.20`; here the pragma is +// WIDENED to `>=0.8.4 <0.9.0` (mirroring the range-pragma convention already used +// for the copied `IExitFeeController.sol`) so it builds against this repo's +// configured 0.8.x compilers. The **ABI is ABI-identical** to upstream (all four +// `record*` signatures, event param lists/indexing, and the full error catalog +// incl. `UnregisteredSource(address)` match byte-for-byte); the only NON-ABI +// divergences are the widened pragma and **whitespace/line-wrap normalized by +// this repo's prettier** (some event/function declarations are re-wrapped). So a +// re-copy MUST compare ABI/selectors, not raw bytes. It is NOT importable from the +// 0.5.17 product hosts (custom `error`s + struct returns need 0.8.x); the 0.5.x +// hooks call the queue through the minimal cross-pragma stub +// `IExitDelayQueueHook.sol` (the four `record*` fns), whose signatures are kept +// byte-for-byte identical to the ones declared below. +// aderyn-ignore-next-line(unspecific-solidity-pragma) +pragma solidity >=0.8.4 <0.9.0; + +/// @title IExitDelayQueue +/// @notice External ABI + type/event/error catalog for `ExitDelayQueue`, the +/// per-request escrow that holds the *user* leg of an exit for a +/// configurable delay so a detected theft can be blocked (frozen or +/// blacklisted) and routed to recovery before the funds leave. +/// +/// This interface mirrors the queue's complete function catalog +/// and its event/error catalog, and declares the shared types. +/// +/// Types (enums/structs) are declared here so cross-pragma callers +/// and off-chain tooling share one source of truth. The queue itself +/// is 0.8.20 UUPS; the four `record*` ingress fns are consumed from +/// 0.5.x / 0.6.x product hosts via a minimal interface stub. +interface IExitDelayQueue { + // ─── Types ─────────────────────────────────────────────────── + + /// @notice Per-request lifecycle. `None` is the zero value (never stored + /// for a live id); the three terminal states are mutually + /// exclusive and a request leaves `Queued` at most once. + enum ExitStatus { + None, // 0 — never recorded + Queued, // 1 — escrowed, awaiting execute / recovery + Executed, // 2 — paid to receiver (terminal) + ResolvedToProtocol, // 3 — Leg-2 recovery-away (terminal) + ResolvedBySIP // 4 — Leg-3 DAO catch-all (terminal) + } + + /// @notice Per-address block state. `Frozen` = temporary (investigating); + /// `Blacklisted` = confirmed hack. Execution treats both as + /// "blocked"; recovery-away distinguishes them. + enum BlockState { + None, // 0 + Frozen, // 1 — temporary, cleared by unfreeze + Blacklisted // 2 — confirmed, cleared only by unblacklist + } + + /// @notice An immutable exit request. Every field except `status` is + /// frozen at record time. Packed into 7 words. + struct ExitRequest { + // word 1 (128 + 64 + 64 = 256 bits): + uint128 amount; // narrowed from the uint256 Perimeter amount at record + uint64 createdAt; // audit/analytics; emitted in ExitQueued + uint64 unlockAt; // COMPUTED by the queue = createdAt + delaySeconds + // words 2-5: + address originator; // withdrawal caller (effective, post-normalization) — block key + executor + address owner; // position owner — MANDATORY block key + executor + address receiver; // immutable payout destination — block key iff freezeReceiver; NOT an executor + address token; // address(0) = native RBTC + // word 6: + bytes32 surfaceId; // provenance: recovery-route key + // word 7 (160 + 8 + 8 = 176 bits): + address subProduct; // provenance: iToken / converter / address(0) + ExitStatus status; // uint8 + bool unwrapOnDelivery; // queue holds WRBTC, executeExit unwraps → native RBTC + } + + /// @notice A pre-approved Leg-2 recovery route. `routeId` is + /// `keccak256(abi.encode(surfaceId, subProduct, token, destination))`. + struct RecoveryRoute { + bool active; + bytes32 surfaceId; + address subProduct; + address token; + address destination; + bool topUpPool; // 2a: plain top-up of the originating pool (destination == subProduct) + } + + // ─── Events ────────────────────────────────────────────────── + + event ExitQueued( + uint256 indexed id, + address indexed originator, + address indexed owner, + address receiver, + address token, + uint128 amount, + uint64 unlockAt, + bytes32 surfaceId, + address subProduct + ); + event ExitExecuted( + uint256 indexed id, + address indexed receiver, + address token, + uint128 amount + ); + event ExitResolvedToProtocol( + uint256 indexed id, + bytes32 indexed routeId, + address destination, + uint128 amount + ); + event ExitResolvedBySIP(uint256 indexed id, address indexed destination, uint128 amount); + event AccountBlocked( + address indexed account, + BlockState state, + uint256 indexed triggerRequestId, + bytes32 reasonHash + ); + event AccountUnblocked(address indexed account, BlockState fromState); + event RecoveryRouteSet( + bytes32 indexed routeId, + bytes32 surfaceId, + address subProduct, + address token, + address destination, + bool topUpPool + ); + event RecoveryRouteRemoved(bytes32 indexed routeId); + event AllowedSourceSet(address indexed source, bool allowed); + event TopUpFeasibleSet(bytes32 indexed surfaceId, bool feasible); + event MinimumDelaySet(uint32 seconds_); + event SecurityPerimeterPausedSet(bool paused); + event NativePusherSet(address indexed pusher); + event SurplusSwept(address indexed token, address indexed to, uint256 amount); + + // ─── Custom errors ─────────────────────────────────────────── + + error UnregisteredSource(address caller); // onlyAllowedSource — DISTINCT record-path halt selector + error ActorBlocked(address actor, BlockState state); // execution-gate revert (event: AccountBlocked) + error NotExecutor(address caller); // msg.sender ∉ {originator, owner} + error NotUnlocked(uint256 id, uint64 unlockAt); + error QueuePaused(); + error AlreadyTerminal(uint256 id); // status != Queued at a transition (also duplicate-batch-id) + error UnknownRequest(uint256 id); + error DelayBelowFloor(uint32 delay, uint32 floor); + error AmountTooLarge(uint256 amount); // uint256→uint128 narrowing guard + error AmountMismatch(uint256 msgValue, uint256 amount); // native value-carrying + error ReceivedAmountMismatch(address token, uint256 have, uint256 want); // pull / measured-delta proof + error ZeroAmount(); + error RouteInactive(bytes32 routeId); + error RouteProvenanceMismatch(uint256 id, bytes32 routeId); + error TopUpInfeasibleSurface(bytes32 surfaceId); // setRecoveryRoute topUpPool guard + error SourceNotBlacklisted(address src); // Leg-2 OR-predicate not satisfied + error NotBlacklisted(address a); // unblacklist on a non-Blacklisted address + error NotFrozen(address a); // unfreeze on a non-Frozen address + error NotResolvableBySIP(uint256 id); // Leg-3 bounded predicate not satisfied + error UnwrapNonWrbtc(); // unwrapOnDelivery set on a non-WRBTC token + error InvalidAltReceiver(address altReceiver); // recoverStuckExit altReceiver ∈ {0,this,token,wrbtc} + error SelfOnly(); // payoutExternal trampoline is self-call-only + error ZeroAddress(); + error EmptyIds(); + error SweepToZero(); + error SolvencyViolated(); // post-sweep balance < totalEscrowed + + // ─── Ingress ───────────────────────────────────────────────── + + /// @dev CALLER-SIDE NARROWING PRECONDITION. Every + /// `record*` takes `amount` as a **`uint128`**, deliberately NOT widened + /// to `uint256`. The Perimeter hook computes the user leg as a `uint256` and + /// MUST narrow it (`uint128(userAmount)`) at the call site; that narrowing + /// is the caller's responsibility and MUST be preceded by the caller's own + /// `require(userAmount <= type(uint128).max)` (`AmountTooLarge`) so a value + /// that would silently truncate is rejected UPSTREAM, before any escrow + /// accounting. The queue keeps `AmountTooLarge` as a defensive + /// queue-boundary guard on the narrowing path — it is NOT dead code: it is + /// the last line of defense if a caller ever omits its own check. Keeping + /// the ABI at `uint128` also packs `amount` into `ExitRequest` word 1 + /// — widening would cost a whole extra storage word per request. + + function recordERC20Exit( + address token, + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver, + bool unwrapOnDelivery + ) external returns (uint256 id); + + function recordReceivedERC20Exit( + address token, + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external returns (uint256 id); + + function recordNativeExit( + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external payable returns (uint256 id); + + function recordReceivedNativeExit( + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external returns (uint256 id); + + // ─── Execution ─────────────────────────────────────────────── + + function executeExit(uint256 requestId) external; + + function executeExits(uint256[] calldata ids) external; + + /// @notice Verify-by-attempting stuck-exit recovery. Callable ONLY by the + /// frozen-metadata `{originator, owner}` set (same as `executeExit`; the + /// receiver is NEVER an executor). Requires the request Queued, unlocked, + /// and the queue not paused. + /// + /// Attempts the STORED-receiver payout FIRST; pays `altReceiver` ONLY if + /// the stored-receiver payout genuinely bounces — so a HEALTHY exit is + /// never redirected (no arbitrary redirect) + /// and there is NO stored failure flag. If `altReceiver` also fails, the + /// whole call reverts (funds stay Queued). + /// + /// Block gate covers ALL FOUR actors — `{originator, owner, STORED + /// receiver, altReceiver}`: a blocked/hacked original receiver refuses + /// recovery entirely (→ Leg-3), so the blacklist trap is preserved + /// rather than turned into an escape hatch, and + /// a permanently undeliverable payout. `altReceiver` is guarded: reverts if it is + /// `0`, this contract, the request token, or WRBTC. The stored request is + /// NEVER re-targeted (`altReceiver` is a payout-time destination only), so + /// request immutability and the block gate still hold. + function recoverStuckExit(uint256 id, address altReceiver) external; + + // ─── Block model ───────────────────────────────────────────── + + function freezeFromRequest( + uint256 requestId, + bool freezeReceiver, + bytes32 reasonHash + ) external; + + function blacklistFromRequest( + uint256 requestId, + bool freezeReceiver, + bytes32 reasonHash + ) external; + + // Batch by-request-id — whole-batch atomic (one bad + // id reverts all, like executeExits); last-write-wins trigger/reason per account. + function freezeFromRequest( + uint256[] calldata requestIds, + bool freezeReceiver, + bytes32 reasonHash + ) external; + + function blacklistFromRequest( + uint256[] calldata requestIds, + bool freezeReceiver, + bytes32 reasonHash + ) external; + + function freeze(address a) external; + + function blacklist(address a) external; + + function unfreeze(address a) external; + + function unblacklist(address a) external; + + // Batch by-address: each reverts `EmptyIds()` on + // an empty array, for API consistency with the by-id batch variants + // (`executeExits` / batch `freezeFromRequest` / `resolveToProtocol` / + // `resolveBySIP`) — an empty batch is a caller mistake, never a silent no-op. + function freeze(address[] calldata a) external; + + function blacklist(address[] calldata a) external; + + function unfreeze(address[] calldata a) external; + + function unblacklist(address[] calldata a) external; + + // ─── Pause ─────────────────────────────────────────────────── + + function setSecurityPerimeterPaused(bool p) external; + + // ─── Recovery ──────────────────────────────────────────────── + + function resolveToProtocol(uint256[] calldata ids, bytes32 routeId) external; + + function resolveBySIP(uint256[] calldata ids, address destination) external; + + function setRecoveryRoute(RecoveryRoute calldata route) external returns (bytes32 routeId); + + function removeRecoveryRoute(bytes32 routeId) external; + + function setTopUpFeasible(bytes32 surfaceId, bool feasible) external; + + // ─── Config ────────────────────────────────────────────────── + + function addAllowedSource(address src) external; + + function removeAllowedSource(address src) external; + + function setNativePusher(address pusher) external; + + function setMinimumDelaySeconds(uint32 s) external; + + function sweepSurplus(address token, address to) external; + + // ─── Views ─────────────────────────────────────────────────── + + function getRequest(uint256 id) external view returns (ExitRequest memory); + + function getActive( + address party, + uint256 cursor, + uint256 n + ) external view returns (uint256[] memory ids, uint256 nextCursor); + + function blockStateOf(address a) external view returns (BlockState); + + /// @notice Paginate the blocked set (Frozen ∪ Blacklisted). + /// @param offset First index into the blocked set to return. + /// @param limit Requested page size; clamped to `MAX_GET_ACTIVE_PAGE` (500). + /// @return page The clamped slice `[offset, offset + page.length)` of the + /// blocked set (empty when `offset >= total` or `limit == 0`). + /// @return total The FULL blocked-set size (EnumerableSet length), independent + /// of `offset`/`limit` — so a caller/monitor knows the whole + /// range ("showing offset..offset+page.length of total") and + /// never silently undercounts past the 500-entry page cap + function blockedAccounts( + uint256 offset, + uint256 limit + ) external view returns (address[] memory page, uint256 total); + + function blockTrigger(address a) external view returns (uint256); + + function totalEscrowed(address token) external view returns (uint256); + + function getRecoveryRoute(bytes32 routeId) external view returns (RecoveryRoute memory); + + function allowedSources() external view returns (address[] memory); + + /// @notice Max page size for the paginated `getActive` / `blockedAccounts` + /// views. Public constant, so paging is + /// self-describing on-chain (500). + function MAX_GET_ACTIVE_PAGE() external view returns (uint256); +} diff --git a/contracts/Interfaces/perimeter/IExitDelayQueueHook.sol b/contracts/Interfaces/perimeter/IExitDelayQueueHook.sol new file mode 100644 index 0000000..c4f185f --- /dev/null +++ b/contracts/Interfaces/perimeter/IExitDelayQueueHook.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// ───────────────────────────────────────────────────────────────────────────── +// Cross-pragma ingress stub for `ExitDelayQueue` (the security-perimeter delay +// queue). The FULL interface + type/event/error catalog lives in +// `IExitDelayQueue.sol` (0.8.20, provenance-locked to +// DistributedCollective/perimeter @ 51457b21). This stub declares ONLY the members +// the 0.5.17 lending + borrower/margin product hooks actually call, so it can be +// imported under the range pragma the product repos compile with. +// +// The four `record*` signatures here are byte-for-byte identical to the FINAL +// ones in `IExitDelayQueue.sol`. Do NOT diverge — the queue's +// IExitDelayQueue is final. +// ───────────────────────────────────────────────────────────────────────────── +// aderyn-ignore-next-line(unspecific-solidity-pragma) +pragma solidity >=0.5.17 <0.9.0; + +/// @title IExitDelayQueueHook +/// @notice The minimal ingress surface the product hooks reach on the queue when +/// the controller quote returns `d > 0`. All ingress is +/// `onlyAllowedSource` on the queue (the record-CALLER must be a +/// registered source): the iToken proxy for lending, the `sovrynProtocol` +/// singleton for borrower/margin. Never called until `d > 0` is +/// established off-queue. +interface IExitDelayQueueHook { + /// @notice ERC20 pull ingress (preferred; also the WRBTC path). The queue does + /// `safeTransferFrom(msg.sender, address(this), amount)` and requires + /// the measured received amount == `amount`. `unwrapOnDelivery` is + /// guarded to `token == WRBTC` at the queue boundary; set it true only + /// for lending `burnToBTC` (escrow WRBTC, unwrap → native at delivery). + function recordERC20Exit( + address token, + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver, + bool unwrapOnDelivery + ) external returns (uint256 id); + + /// @notice ERC20 measured-delta ingress: the source PUSHES `amount` to the + /// queue first, then records in the SAME outer transaction. The queue + /// measures `delta = balanceOf(token) - totalEscrowed[token]`, requires + /// `delta >= amount`, and credits EXACTLY `amount`. Used by the + /// borrower/margin surface (push via `vaultWithdraw` then record). + function recordReceivedERC20Exit( + address token, + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external returns (uint256 id); + + /// @notice Native value-carrying ingress: `require(msg.value == amount)`; + /// token is implicitly `address(0)`. + function recordNativeExit( + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external payable returns (uint256 id); + + /// @notice Native measured-receipt ingress: the native RBTC is pushed to the + /// queue's `receive()` first (e.g. `vaultEtherWithdraw(queue, amount)`), + /// then recorded in the SAME outer transaction. The queue measures + /// `delta = address(this).balance - totalEscrowed[address(0)]`, requires + /// `delta >= amount`, and credits EXACTLY `amount`. Used by the + /// borrower/margin native-collateral path. + function recordReceivedNativeExit( + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external returns (uint256 id); +} diff --git a/contracts/Interfaces/perimeter/IExitFeeController.sol b/contracts/Interfaces/perimeter/IExitFeeController.sol index de2d6c8..51f5208 100644 --- a/contracts/Interfaces/perimeter/IExitFeeController.sol +++ b/contracts/Interfaces/perimeter/IExitFeeController.sol @@ -1,12 +1,28 @@ // SPDX-License-Identifier: MIT // ───────────────────────────────────────────────────────────────────────────── -// Vendored copy of the Perimeter exit-fee controller interface, taken from -// DistributedCollective/perimeter @ c85f60aef91bc644517cf1b3ea7c5e8c565f4ca5 +// Curated cross-pragma subset of the exit-fee controller interface, derived from +// DistributedCollective/perimeter @ 51457b21bc9a87958e99ea51325ded150422e791 // src/interfaces/IExitFeeController.sol -// Do not change the declarations here: the binding property is ABI equality with -// the deployed controller. To pick up an interface change, change it upstream, -// re-copy, and bump the SHA above. Local formatting follows this repo's -// formatter, so the file is not byte-identical to the upstream source. +// +// This is a deliberate SUBSET, not a verbatim copy: it declares only the members +// the product hooks call — `quoteExitFee`, the delay members `quoteExitDelayFor` +// / `quoteExitDelay` / `effectiveActor`, and the bypass/passthrough read views. +// It omits the upstream governance, enumeration and admin surface, which is used +// only by the 0.8.20 controller implementation and its tooling, never by a +// 0.6.11 hook. +// +// The binding property is ABI equality with the deployed controller for the +// members declared here. In particular +// quoteExitDelayFor(address,address,address,bytes32,address) +// view returns (uint32, address, address) +// is byte-identical to upstream and MUST stay so — `BorrowerOperations. +// _safeQuoteExitDelay` calls it. +// +// To update: re-derive from upstream at a known SHA rather than blind-copying +// (a copy that trims back to the upstream member list would delete +// `quoteExitDelayFor`), keep the subset to what the hosts need, and bump the SHA +// above. Local formatting follows this repo's formatter, so the file is not +// byte-identical to the upstream source. // ───────────────────────────────────────────────────────────────────────────── // Range pragma is intentional: the same declarations are compiled under Solidity // 0.5.17, 0.6.11 (this repo), and 0.8.20. @@ -54,6 +70,18 @@ interface IExitFeeController { uint16 rateBps; } + /// @notice A delay bypass/exemption entry, mirroring the fee tiers + /// (actor → sub-product → surface). `active == false` ⇒ the tier is + /// not configured; resolution falls through. `active == true` ⇒ this + /// tier decides: `bypass == true` exempts (`d = 0`), `bypass == false` + /// FORCES `globalDelaySeconds` (overriding a broader bypass). It is an + /// exemption toggle only — there is no per-instance delay + /// duration. Copied final from perimeter. + struct DelayBypassPolicy { + bool active; + bool bypass; + } + /// @notice Quote returned by `quoteExitFee`. `reason` carries the precise /// off-state code; `active` is the resolved policy state (true iff /// a RatePolicy.active entry was used and reason ∈ {NONE}). @@ -86,6 +114,28 @@ interface IExitFeeController { event SubProductPolicyRemoved(bytes32 indexed surfaceId, address indexed subProduct); event ActorPolicyRemoved(bytes32 indexed surfaceId, address indexed actor); + // Delay extension. + event SecurityPerimeterEnabledSet(bool enabled); + event GlobalDelaySet(uint32 seconds_); + event SurfaceBypassSet(bytes32 indexed surfaceId, bool active, bool bypass); + event SubProductBypassSet( + bytes32 indexed surfaceId, + address indexed subProduct, + bool active, + bool bypass + ); + event ActorBypassSet( + bytes32 indexed surfaceId, + address indexed actor, + bool active, + bool bypass + ); + event PassthroughActorSet( + bytes32 indexed surfaceId, + address indexed actor, + bool isPassthrough + ); + // ─── Quote ──────────────────────────────────────────────────────────── /// @notice Resolve the fee policy for `(surfaceId, subProduct, actor)` and @@ -100,6 +150,42 @@ interface IExitFeeController { uint256 grossAmount ) external view returns (ExitFeeQuote memory); + // ─── Delay quote (security perimeter) ───────────────────────────────── + + /// @notice The hook's SINGLE delay entry. Short-circuits the kill + /// switch FIRST: `if (!securityPerimeterEnabled) return (0, + /// rawOriginator, owner)` (pays direct without touching the queue). + /// Otherwise resolves the surface-scoped effective actors, quotes on + /// `effOrig`, and returns all three — so the quote and the record use + /// the SAME identity (Finding 2). The hook MUST ignore `effOrig` / + /// `effOwner` and pay direct whenever `d == 0`. + /// @return d Delay seconds to escrow for (0 ⇒ off / inactive / bypassed). + /// @return effOrig Effective originator (raw, or passthrough→receiver). + /// @return effOwner Effective owner (raw, or passthrough→receiver). + function quoteExitDelayFor( + address rawOriginator, + address owner, + address receiver, + bytes32 surfaceId, + address subProduct + ) external view returns (uint32 d, address effOrig, address effOwner); + + /// @notice Inner per-actor delay view (off / inactive / bypass ⇒ 0, else + /// `globalDelaySeconds`) on an already-effective actor; off-chain use. + function quoteExitDelay( + bytes32 surfaceId, + address subProduct, + address effectiveActor + ) external view returns (uint32); + + /// @notice Resolve a surface-scoped passthrough: a passthrough registered for + /// `surfaceId` resolves `raw` to `receiver`, else identity. + function effectiveActor( + bytes32 surfaceId, + address raw, + address receiver + ) external view returns (address); + // ─── State views ────────────────────────────────────────────────────── function exitFeeEnabled() external view returns (bool); @@ -122,6 +208,26 @@ interface IExitFeeController { function actorKeys(bytes32 surfaceId) external view returns (address[] memory); + // ─── Delay state views ──────────────────────────────────────────────── + + function securityPerimeterEnabled() external view returns (bool); + + function globalDelaySeconds() external view returns (uint32); + + function surfaceBypass(bytes32 surfaceId) external view returns (DelayBypassPolicy memory); + + function subProductBypass( + bytes32 surfaceId, + address subProduct + ) external view returns (DelayBypassPolicy memory); + + function actorBypass( + bytes32 surfaceId, + address actor + ) external view returns (DelayBypassPolicy memory); + + function passthroughActor(bytes32 surfaceId, address a) external view returns (bool); + // ─── Admin ──────────────────────────────────────────────────────────── function setExitFeeEnabled(bool enabled) external; @@ -157,4 +263,28 @@ interface IExitFeeController { function removeActorPolicy(bytes32 surfaceId, address actor) external; function removeActorPolicies(bytes32 surfaceId, address[] calldata actors) external; + + // ─── Delay admin (security perimeter) ───────────────────────────────── + // The kill switch is `onlyAdminOrOwner`; every other delay setter is + // `onlyOwner`. View quotes are ungated. + + function setSecurityPerimeterEnabled(bool enabled) external; + + function setGlobalDelaySeconds(uint32 seconds_) external; + + function setSurfaceBypass(bytes32 surfaceId, DelayBypassPolicy calldata policy) external; + + function setSubProductBypass( + bytes32 surfaceId, + address subProduct, + DelayBypassPolicy calldata policy + ) external; + + function setActorBypass( + bytes32 surfaceId, + address actor, + DelayBypassPolicy calldata policy + ) external; + + function setPassthroughActor(bytes32 surfaceId, address a, bool isPassthrough) external; } diff --git a/contracts/MultiTroveGetter.sol b/contracts/MultiTroveGetter.sol index 006cf15..3f17fc7 100644 --- a/contracts/MultiTroveGetter.sol +++ b/contracts/MultiTroveGetter.sol @@ -18,19 +18,18 @@ contract MultiTroveGetter is MultiTroveGetterStorage { uint256 snapshotZUSDDebt; } - function setAddresses(TroveManager _troveManager, ISortedTroves _sortedTroves) - public - onlyOwner - { + function setAddresses( + TroveManager _troveManager, + ISortedTroves _sortedTroves + ) public onlyOwner { troveManager = _troveManager; sortedTroves = _sortedTroves; } - function getMultipleSortedTroves(int256 _startIdx, uint256 _count) - external - view - returns (CombinedTroveData[] memory _troves) - { + function getMultipleSortedTroves( + int256 _startIdx, + uint256 _count + ) external view returns (CombinedTroveData[] memory _troves) { uint256 startIdx; bool descend; @@ -61,11 +60,10 @@ contract MultiTroveGetter is MultiTroveGetterStorage { } } - function _getMultipleSortedTrovesFromHead(uint256 _startIdx, uint256 _count) - internal - view - returns (CombinedTroveData[] memory _troves) - { + function _getMultipleSortedTrovesFromHead( + uint256 _startIdx, + uint256 _count + ) internal view returns (CombinedTroveData[] memory _troves) { address currentTroveowner = sortedTroves.getFirst(); for (uint256 idx = 0; idx < _startIdx; ++idx) { @@ -92,11 +90,10 @@ contract MultiTroveGetter is MultiTroveGetterStorage { } } - function _getMultipleSortedTrovesFromTail(uint256 _startIdx, uint256 _count) - internal - view - returns (CombinedTroveData[] memory _troves) - { + function _getMultipleSortedTrovesFromTail( + uint256 _startIdx, + uint256 _count + ) internal view returns (CombinedTroveData[] memory _troves) { address currentTroveowner = sortedTroves.getLast(); for (uint256 idx = 0; idx < _startIdx; ++idx) { diff --git a/contracts/PriceFeed.sol b/contracts/PriceFeed.sol index 4bf046a..9cbcc39 100644 --- a/contracts/PriceFeed.sol +++ b/contracts/PriceFeed.sol @@ -39,7 +39,7 @@ contract PriceFeed is PriceFeedStorage, IPriceFeed { emit PriceFeedBroken(index, address(priceFeeds[index])); } } - + revert("PriceFeed: Price feed price is stale"); } @@ -62,7 +62,7 @@ contract PriceFeed is PriceFeedStorage, IPriceFeed { emit LastGoodPriceUpdated(_currentPrice); } - function getPriceFeedAtIndex(uint8 _index) external view returns(address) { + function getPriceFeedAtIndex(uint8 _index) external view returns (address) { return address(priceFeeds[_index]); } } diff --git a/contracts/Proxy/BorrowerOperationsScript.sol b/contracts/Proxy/BorrowerOperationsScript.sol index e8a1d3e..f7c9c61 100644 --- a/contracts/Proxy/BorrowerOperationsScript.sol +++ b/contracts/Proxy/BorrowerOperationsScript.sol @@ -5,7 +5,6 @@ pragma solidity 0.6.11; import "../Dependencies/CheckContract.sol"; import "../Interfaces/IBorrowerOperations.sol"; - contract BorrowerOperationsScript is CheckContract { IBorrowerOperations immutable borrowerOperations; @@ -14,8 +13,18 @@ contract BorrowerOperationsScript is CheckContract { borrowerOperations = _borrowerOperations; } - function openTrove(uint _maxFee, uint _ZUSDAmount, address _upperHint, address _lowerHint) external payable { - borrowerOperations.openTrove{ value: msg.value }(_maxFee, _ZUSDAmount, _upperHint, _lowerHint); + function openTrove( + uint _maxFee, + uint _ZUSDAmount, + address _upperHint, + address _lowerHint + ) external payable { + borrowerOperations.openTrove{ value: msg.value }( + _maxFee, + _ZUSDAmount, + _upperHint, + _lowerHint + ); } function addColl(address _upperHint, address _lowerHint) external payable { @@ -26,7 +35,12 @@ contract BorrowerOperationsScript is CheckContract { borrowerOperations.withdrawColl(_amount, _upperHint, _lowerHint); } - function withdrawZUSD(uint _maxFee, uint _amount, address _upperHint, address _lowerHint) external { + function withdrawZUSD( + uint _maxFee, + uint _amount, + address _upperHint, + address _lowerHint + ) external { borrowerOperations.withdrawZUSD(_maxFee, _amount, _upperHint, _lowerHint); } @@ -38,8 +52,22 @@ contract BorrowerOperationsScript is CheckContract { borrowerOperations.closeTrove(); } - function adjustTrove(uint _maxFee, uint _collWithdrawal, uint _debtChange, bool isDebtIncrease, address _upperHint, address _lowerHint) external payable { - borrowerOperations.adjustTrove{ value: msg.value }(_maxFee, _collWithdrawal, _debtChange, isDebtIncrease, _upperHint, _lowerHint); + function adjustTrove( + uint _maxFee, + uint _collWithdrawal, + uint _debtChange, + bool isDebtIncrease, + address _upperHint, + address _lowerHint + ) external payable { + borrowerOperations.adjustTrove{ value: msg.value }( + _maxFee, + _collWithdrawal, + _debtChange, + isDebtIncrease, + _upperHint, + _lowerHint + ); } function claimCollateral() external { diff --git a/contracts/Proxy/BorrowerWrappersScript.sol b/contracts/Proxy/BorrowerWrappersScript.sol index a06b677..4b08fd9 100644 --- a/contracts/Proxy/BorrowerWrappersScript.sol +++ b/contracts/Proxy/BorrowerWrappersScript.sol @@ -15,11 +15,10 @@ import "./ETHTransferScript.sol"; import "./ZEROStakingScript.sol"; import "../Dependencies/console.sol"; - contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, ZEROStakingScript { using SafeMath for uint; - string constant public NAME = "BorrowerWrappersScript"; + string public constant NAME = "BorrowerWrappersScript"; ITroveManager immutable troveManager; IStabilityPool immutable stabilityPool; @@ -37,9 +36,9 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, address _zusdTokenAddress, address _zeroTokenAddress ) + public BorrowerOperationsScript(IBorrowerOperations(_borrowerOperationsAddress)) ZEROStakingScript(_zeroStakingAddress) - public { checkContract(_troveManagerAddress); ITroveManager troveManagerCached = ITroveManager(_troveManagerAddress); @@ -49,7 +48,7 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, checkContract(_stabilityPoolAddress); stabilityPool = stabilityPoolCached; - IPriceFeed priceFeedCached = IPriceFeed(_priceFeedAddress); + IPriceFeed priceFeedCached = IPriceFeed(_priceFeedAddress); checkContract(_priceFeedAddress); priceFeed = priceFeedCached; @@ -64,7 +63,12 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, zeroStaking = zeroStakingCached; } - function claimCollateralAndOpenTrove(uint _maxFee, uint _ZUSDAmount, address _upperHint, address _lowerHint) external payable { + function claimCollateralAndOpenTrove( + uint _maxFee, + uint _ZUSDAmount, + address _upperHint, + address _lowerHint + ) external payable { uint balanceBefore = address(this).balance; // Claim collateral @@ -78,10 +82,19 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, uint totalCollateral = balanceAfter.sub(balanceBefore).add(msg.value); // Open trove with obtained collateral, plus collateral sent by user - borrowerOperations.openTrove{ value: totalCollateral }(_maxFee, _ZUSDAmount, _upperHint, _lowerHint); + borrowerOperations.openTrove{ value: totalCollateral }( + _maxFee, + _ZUSDAmount, + _upperHint, + _lowerHint + ); } - function claimSPRewardsAndRecycle(uint _maxFee, address _upperHint, address _lowerHint) external { + function claimSPRewardsAndRecycle( + uint _maxFee, + address _upperHint, + address _lowerHint + ) external { uint collBalanceBefore = address(this).balance; uint zeroBalanceBefore = zeroToken.balanceOf(address(this)); @@ -96,7 +109,14 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, if (claimedCollateral > 0) { _requireUserHasTrove(address(this)); uint ZUSDAmount = _getNetZUSDAmount(claimedCollateral); - borrowerOperations.adjustTrove{ value: claimedCollateral }(_maxFee, 0, ZUSDAmount, true, _upperHint, _lowerHint); + borrowerOperations.adjustTrove{ value: claimedCollateral }( + _maxFee, + 0, + ZUSDAmount, + true, + _upperHint, + _lowerHint + ); // Provide withdrawn ZUSD to Stability Pool if (ZUSDAmount > 0) { stabilityPool.provideToSP(ZUSDAmount, address(0)); @@ -110,7 +130,11 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, } } - function claimStakingGainsAndRecycle(uint _maxFee, address _upperHint, address _lowerHint) external { + function claimStakingGainsAndRecycle( + uint _maxFee, + address _upperHint, + address _lowerHint + ) external { uint collBalanceBefore = address(this).balance; uint zusdBalanceBefore = zusdToken.balanceOf(address(this)); uint zeroBalanceBefore = zeroToken.balanceOf(address(this)); @@ -126,7 +150,14 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, if (gainedCollateral > 0) { _requireUserHasTrove(address(this)); netZUSDAmount = _getNetZUSDAmount(gainedCollateral); - borrowerOperations.adjustTrove{ value: gainedCollateral }(_maxFee, 0, netZUSDAmount, true, _upperHint, _lowerHint); + borrowerOperations.adjustTrove{ value: gainedCollateral }( + _maxFee, + 0, + netZUSDAmount, + true, + _upperHint, + _lowerHint + ); } uint totalZUSD = gainedZUSD.add(netZUSDAmount); @@ -140,7 +171,6 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, zeroStaking.stake(claimedZERO); } } - } function _getNetZUSDAmount(uint _collateral) internal returns (uint) { @@ -149,12 +179,17 @@ contract BorrowerWrappersScript is BorrowerOperationsScript, ETHTransferScript, uint ZUSDAmount = _collateral.mul(price).div(ICR); uint borrowingRate = troveManager.getBorrowingRateWithDecay(); - uint netDebt = ZUSDAmount.mul(LiquityMath.DECIMAL_PRECISION).div(LiquityMath.DECIMAL_PRECISION.add(borrowingRate)); + uint netDebt = ZUSDAmount.mul(LiquityMath.DECIMAL_PRECISION).div( + LiquityMath.DECIMAL_PRECISION.add(borrowingRate) + ); return netDebt; } function _requireUserHasTrove(address _depositor) internal view { - require(troveManager.getTroveStatus(_depositor) == 1, "BorrowerWrappersScript: caller must have an active trove"); + require( + troveManager.getTroveStatus(_depositor) == 1, + "BorrowerWrappersScript: caller must have an active trove" + ); } } diff --git a/contracts/Proxy/ETHTransferScript.sol b/contracts/Proxy/ETHTransferScript.sol index ce70c91..0bd109b 100644 --- a/contracts/Proxy/ETHTransferScript.sol +++ b/contracts/Proxy/ETHTransferScript.sol @@ -2,10 +2,9 @@ pragma solidity 0.6.11; - contract ETHTransferScript { function transferETH(address _recipient, uint256 _amount) external returns (bool) { - (bool success, ) = _recipient.call{value: _amount}(""); + (bool success, ) = _recipient.call{ value: _amount }(""); return success; } } diff --git a/contracts/Proxy/Proxy.sol b/contracts/Proxy/Proxy.sol index 81ba359..4cff6d1 100644 --- a/contracts/Proxy/Proxy.sol +++ b/contracts/Proxy/Proxy.sol @@ -2,10 +2,11 @@ pragma solidity 0.6.11; import "../Dependencies/Ownable.sol"; + /** * @title Base Proxy contract. - * - * Adapted version of https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/development/contracts/proxy/Proxy.sol + * + * Adapted version of https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/development/contracts/proxy/Proxy.sol * * @notice The proxy performs delegated calls to the contract implementation * it is pointing to. This way upgradable contracts are possible on blockchain. diff --git a/contracts/Proxy/StabilityPoolScript.sol b/contracts/Proxy/StabilityPoolScript.sol index d6aca5e..6a68f8f 100644 --- a/contracts/Proxy/StabilityPoolScript.sol +++ b/contracts/Proxy/StabilityPoolScript.sol @@ -5,9 +5,8 @@ pragma solidity 0.6.11; import "../Dependencies/CheckContract.sol"; import "../Interfaces/IStabilityPool.sol"; - contract StabilityPoolScript is CheckContract { - string constant public NAME = "StabilityPoolScript"; + string public constant NAME = "StabilityPoolScript"; IStabilityPool immutable stabilityPool; diff --git a/contracts/Proxy/TokenScript.sol b/contracts/Proxy/TokenScript.sol index ddfc13d..8a1b789 100644 --- a/contracts/Proxy/TokenScript.sol +++ b/contracts/Proxy/TokenScript.sol @@ -5,9 +5,8 @@ pragma solidity 0.6.11; import "../Dependencies/CheckContract.sol"; import "../Dependencies/IERC20.sol"; - contract TokenScript is CheckContract { - string constant public NAME = "TokenScript"; + string public constant NAME = "TokenScript"; IERC20 immutable token; @@ -28,7 +27,11 @@ contract TokenScript is CheckContract { token.approve(spender, amount); } - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) { + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool) { token.transferFrom(sender, recipient, amount); } diff --git a/contracts/Proxy/TroveManagerScript.sol b/contracts/Proxy/TroveManagerScript.sol index 99e6bb7..cd1c961 100644 --- a/contracts/Proxy/TroveManagerScript.sol +++ b/contracts/Proxy/TroveManagerScript.sol @@ -5,9 +5,8 @@ pragma solidity 0.6.11; import "../Dependencies/CheckContract.sol"; import "../Interfaces/ITroveManager.sol"; - contract TroveManagerScript is CheckContract { - string constant public NAME = "TroveManagerScript"; + string public constant NAME = "TroveManagerScript"; ITroveManager immutable troveManager; diff --git a/contracts/Proxy/UpgradableProxy.sol b/contracts/Proxy/UpgradableProxy.sol index 8754fb7..f76ff30 100644 --- a/contracts/Proxy/UpgradableProxy.sol +++ b/contracts/Proxy/UpgradableProxy.sol @@ -7,7 +7,7 @@ import "./Proxy.sol"; * @title Upgradable Proxy contract. * * Adapted version of https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/development/contracts/proxy/UpgradableProxy.sol - * + * * @notice A disadvantage of the immutable ledger is that nobody can change the * source code of a smart contract after it’s been deployed. In order to fix * bugs or introduce new features, smart contracts need to be upgradable somehow. @@ -32,5 +32,4 @@ contract UpgradableProxy is Proxy { function setImplementation(address _implementation) public onlyOwner { _setImplementation(_implementation); } - } diff --git a/contracts/Proxy/ZEROStakingScript.sol b/contracts/Proxy/ZEROStakingScript.sol index f4100a9..6a32a3f 100644 --- a/contracts/Proxy/ZEROStakingScript.sol +++ b/contracts/Proxy/ZEROStakingScript.sol @@ -5,7 +5,6 @@ pragma solidity 0.6.11; import "../Dependencies/CheckContract.sol"; import "../Interfaces/IZEROStaking.sol"; - contract ZEROStakingScript is CheckContract { IZEROStaking immutable ZEROStaking; diff --git a/contracts/StabilityPool.sol b/contracts/StabilityPool.sol index d0f6f46..0a590ff 100644 --- a/contracts/StabilityPool.sol +++ b/contracts/StabilityPool.sol @@ -486,10 +486,10 @@ contract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, ISta emit G_Updated(epochToScaleToG[currentEpoch][currentScale], currentEpoch, currentScale); } - function _computeSOVPerUnitStaked(uint256 _SOVIssuance, uint256 _totalZUSDDeposits) - internal - returns (uint256) - { + function _computeSOVPerUnitStaked( + uint256 _SOVIssuance, + uint256 _totalZUSDDeposits + ) internal returns (uint256) { /* * Calculate the SOV-per-unit staked. Division uses a "feedback" error correction, to keep the * cumulative error low in the running total G: @@ -672,11 +672,10 @@ contract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, ISta return ETHGain; } - function _getETHGainFromSnapshots(uint256 initialDeposit, Snapshots memory snapshots) - internal - view - returns (uint256) - { + function _getETHGainFromSnapshots( + uint256 initialDeposit, + Snapshots memory snapshots + ) internal view returns (uint256) { /* * Grab the sum 'S' from the epoch at which the stake was made. The ETH gain may span up to one scale change. * If it does, the second portion of the ETH gain is scaled by 1e9. @@ -754,11 +753,10 @@ contract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, ISta return SOVGain; } - function _getSOVGainFromSnapshots(uint256 initialStake, Snapshots memory snapshots) - internal - view - returns (uint256) - { + function _getSOVGainFromSnapshots( + uint256 initialStake, + Snapshots memory snapshots + ) internal view returns (uint256) { /* * Grab the sum 'G' from the epoch at which the stake was made. The SOV gain may span up to one scale change. * If it does, the second portion of the SOV gain is scaled by 1e9. @@ -822,11 +820,10 @@ contract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, ISta } // Internal function, used to calculcate compounded deposits and compounded front end stakes. - function _getCompoundedStakeFromSnapshots(uint256 initialStake, Snapshots memory snapshots) - internal - view - returns (uint256) - { + function _getCompoundedStakeFromSnapshots( + uint256 initialStake, + Snapshots memory snapshots + ) internal view returns (uint256) { uint256 snapshot_P = snapshots.P; uint128 scaleSnapshot = snapshots.scale; uint128 epochSnapshot = snapshots.epoch; diff --git a/contracts/TestContracts/ActivePoolTester.sol b/contracts/TestContracts/ActivePoolTester.sol index 20f8940..e816da6 100644 --- a/contracts/TestContracts/ActivePoolTester.sol +++ b/contracts/TestContracts/ActivePoolTester.sol @@ -5,9 +5,8 @@ pragma solidity 0.6.11; import "../ActivePool.sol"; contract ActivePoolTester is ActivePool { - function unprotectedIncreaseZUSDDebt(uint _amount) external { - ZUSDDebt = ZUSDDebt.add(_amount); + ZUSDDebt = ZUSDDebt.add(_amount); } function unprotectedPayable() external payable { diff --git a/contracts/TestContracts/BorrowerOperationsTester.sol b/contracts/TestContracts/BorrowerOperationsTester.sol index f13b9ce..3bdfef1 100644 --- a/contracts/TestContracts/BorrowerOperationsTester.sol +++ b/contracts/TestContracts/BorrowerOperationsTester.sol @@ -4,63 +4,76 @@ pragma solidity 0.6.11; pragma experimental ABIEncoderV2; import "../BorrowerOperations.sol"; +import "../Dependencies/BorrowerOperationsPerimeterOps.sol"; /* Tester contract inherits from BorrowerOperations, and provides external functions for testing the parent's internal functions. */ contract BorrowerOperationsTester is BorrowerOperations { + constructor(address _permit2) public BorrowerOperations(_permit2) { + perimeterOps = address(new BorrowerOperationsPerimeterOps()); + } - constructor(address _permit2) public BorrowerOperations(_permit2) {} - - function getNewICRFromTroveChange - ( - uint _coll, - uint _debt, - uint _collChange, - bool isCollIncrease, - uint _debtChange, - bool isDebtIncrease, + function getNewICRFromTroveChange( + uint _coll, + uint _debt, + uint _collChange, + bool isCollIncrease, + uint _debtChange, + bool isDebtIncrease, uint _price - ) - external - pure - returns (uint) - { - return _getNewICRFromTroveChange(_coll, _debt, _collChange, isCollIncrease, _debtChange, isDebtIncrease, _price); + ) external pure returns (uint) { + return + _getNewICRFromTroveChange( + _coll, + _debt, + _collChange, + isCollIncrease, + _debtChange, + isDebtIncrease, + _price + ); } - function getNewTCRFromTroveChange - ( - uint _collChange, - bool isCollIncrease, - uint _debtChange, - bool isDebtIncrease, + function getNewTCRFromTroveChange( + uint _collChange, + bool isCollIncrease, + uint _debtChange, + bool isDebtIncrease, uint _price - ) - external - view - returns (uint) - { - return _getNewTCRFromTroveChange(_collChange, isCollIncrease, _debtChange, isDebtIncrease, _price); + ) external view returns (uint) { + return + _getNewTCRFromTroveChange( + _collChange, + isCollIncrease, + _debtChange, + isDebtIncrease, + _price + ); } function getUSDValue(uint _coll, uint _price) external pure returns (uint) { return _getUSDValue(_coll, _price); } - function callInternalAdjustLoan - ( - address _borrower, - uint _collWithdrawal, - uint _debtChange, - bool _isDebtIncrease, + function callInternalAdjustLoan( + address _borrower, + uint _collWithdrawal, + uint _debtChange, + bool _isDebtIncrease, address _upperHint, - address _lowerHint) - external - { - _adjustTrove(_borrower, _collWithdrawal, _debtChange, _isDebtIncrease, _upperHint, _lowerHint, 0); + address _lowerHint + ) external { + _adjustTrove( + _borrower, + _collWithdrawal, + _debtChange, + _isDebtIncrease, + _upperHint, + _lowerHint, + 0 + ); } - // Payable fallback function - receive() external payable { } + receive() external payable {} } diff --git a/contracts/TestContracts/CommunityIssuanceTester.sol b/contracts/TestContracts/CommunityIssuanceTester.sol index 8ab3c31..875e4d8 100644 --- a/contracts/TestContracts/CommunityIssuanceTester.sol +++ b/contracts/TestContracts/CommunityIssuanceTester.sol @@ -6,12 +6,12 @@ import "../ZERO/CommunityIssuance.sol"; contract CommunityIssuanceTester is CommunityIssuance { function obtainSOV(uint _amount) external { - sovToken.transfer(msg.sender, _amount); + sovToken.transfer(msg.sender, _amount); } function unprotectedIssueSOV(uint256 _totalZUSDDeposits) external returns (uint) { - // No checks on caller address - - return _issueSOV(_totalZUSDDeposits); + // No checks on caller address + + return _issueSOV(_totalZUSDDeposits); } } diff --git a/contracts/TestContracts/DappSys/proxy.sol b/contracts/TestContracts/DappSys/proxy.sol index 062df94..5f9b86e 100644 --- a/contracts/TestContracts/DappSys/proxy.sol +++ b/contracts/TestContracts/DappSys/proxy.sol @@ -1,7 +1,7 @@ // From: https://etherscan.io/address/0xa26e15c895efc0616177b7c1e7270a4c7d51c997#code /** *Submitted for verification at Etherscan.io on 2018-06-22 -*/ + */ // proxy.sol - execute actions atomically through the proxy's identity @@ -25,42 +25,34 @@ pragma solidity 0.6.11; abstract contract DSAuthority { - function canCall( - address src, address dst, bytes4 sig - ) virtual public view returns (bool); + function canCall(address src, address dst, bytes4 sig) public view virtual returns (bool); } contract DSAuthEvents { - event LogSetAuthority (address indexed authority); - event LogSetOwner (address indexed owner); + event LogSetAuthority(address indexed authority); + event LogSetOwner(address indexed owner); } contract DSAuth is DSAuthEvents { - DSAuthority public authority; - address public owner; + DSAuthority public authority; + address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } - function setOwner(address owner_) - public - auth - { + function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } - function setAuthority(DSAuthority authority_) - public - auth - { + function setAuthority(DSAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(address(authority)); } - modifier auth { + modifier auth() { require(isAuthorized(msg.sender, msg.sig)); _; } @@ -80,15 +72,15 @@ contract DSAuth is DSAuthEvents { contract DSNote { event LogNote( - bytes4 indexed sig, - address indexed guy, - bytes32 indexed foo, - bytes32 indexed bar, - uint wad, - bytes fax + bytes4 indexed sig, + address indexed guy, + bytes32 indexed foo, + bytes32 indexed bar, + uint wad, + bytes fax ) anonymous; - modifier note { + modifier note() { bytes32 foo; bytes32 bar; @@ -109,23 +101,21 @@ contract DSNote { // the proxy can be changed, this allows for dynamic ownership models // i.e. a multisig contract DSProxy is DSAuth, DSNote { - DSProxyCache public cache; // global cache for contracts + DSProxyCache public cache; // global cache for contracts constructor(address _cacheAddr) public { require(setCache(_cacheAddr)); } - fallback() external payable { - } - receive() external payable { - } + fallback() external payable {} + + receive() external payable {} // use the proxy to execute calldata _data on contract _code - function execute(bytes calldata _code, bytes calldata _data) - public - payable - returns (address target, bytes32 response) - { + function execute( + bytes calldata _code, + bytes calldata _data + ) public payable returns (address target, bytes32 response) { target = cache.read(_code); if (target == address(0x0)) { // deploy contract & store its address in cache @@ -135,19 +125,23 @@ contract DSProxy is DSAuth, DSNote { response = execute(target, _data); } - function execute(address _target, bytes memory _data) - public - auth - note - payable - returns (bytes32 response) - { + function execute( + address _target, + bytes memory _data + ) public payable auth note returns (bytes32 response) { require(_target != address(0x0)); // call contract in current context assembly { - let succeeded := delegatecall(sub(gas(), 5000), _target, add(_data, 0x20), mload(_data), 0, 32) - response := mload(0) // load delegatecall output + let succeeded := delegatecall( + sub(gas(), 5000), + _target, + add(_data, 0x20), + mload(_data), + 0, + 32 + ) + response := mload(0) // load delegatecall output switch iszero(succeeded) case 1 { // throw if delegatecall failed @@ -157,14 +151,9 @@ contract DSProxy is DSAuth, DSNote { } //set new cache - function setCache(address _cacheAddr) - internal - auth - note - returns (bool) - { - require(_cacheAddr != address(0x0)); // invalid cache address - cache = DSProxyCache(_cacheAddr); // overwrite cache + function setCache(address _cacheAddr) internal auth note returns (bool) { + require(_cacheAddr != address(0x0)); // invalid cache address + cache = DSProxyCache(_cacheAddr); // overwrite cache return true; } } @@ -174,7 +163,7 @@ contract DSProxy is DSAuth, DSNote { // Deployed proxy addresses are logged contract DSProxyFactory { event Created(address indexed sender, address indexed owner, address proxy, address cache); - mapping(address=>bool) public isProxy; + mapping(address => bool) public isProxy; DSProxyCache public cache = new DSProxyCache(); // deploys a new proxy instance diff --git a/contracts/TestContracts/DefaultPoolTester.sol b/contracts/TestContracts/DefaultPoolTester.sol index be72bca..7ea0f31 100644 --- a/contracts/TestContracts/DefaultPoolTester.sol +++ b/contracts/TestContracts/DefaultPoolTester.sol @@ -5,9 +5,8 @@ pragma solidity 0.6.11; import "../DefaultPool.sol"; contract DefaultPoolTester is DefaultPool { - function unprotectedIncreaseZUSDDebt(uint _amount) external { - ZUSDDebt = ZUSDDebt.add(_amount); + ZUSDDebt = ZUSDDebt.add(_amount); } function unprotectedPayable() external payable { diff --git a/contracts/TestContracts/Destructible.sol b/contracts/TestContracts/Destructible.sol index 2950986..3a50274 100644 --- a/contracts/TestContracts/Destructible.sol +++ b/contracts/TestContracts/Destructible.sol @@ -3,9 +3,8 @@ pragma solidity 0.6.11; contract Destructible { - receive() external payable {} - + function destruct(address payable _receiver) external { selfdestruct(_receiver); } diff --git a/contracts/TestContracts/EchidnaTester.sol b/contracts/TestContracts/EchidnaTester.sol index ed94914..bcb0bfe 100644 --- a/contracts/TestContracts/EchidnaTester.sol +++ b/contracts/TestContracts/EchidnaTester.sol @@ -9,6 +9,7 @@ import "../TroveManager.sol"; import "../TroveManagerStorage.sol"; import "../Dependencies/TroveManagerRedeemOps.sol"; import "../BorrowerOperations.sol"; +import "../Dependencies/BorrowerOperationsPerimeterOps.sol"; import "../ActivePool.sol"; import "../DefaultPool.sol"; import "../StabilityPool.sol"; @@ -58,6 +59,7 @@ contract EchidnaTester { troveManagerRedeemOps = new TroveManagerRedeemOps(14 * 86400, _permit2); troveManager = new TroveManager(14 days, _permit2); borrowerOperations = new BorrowerOperations(_permit2); + borrowerOperations.setPerimeterOps(address(new BorrowerOperationsPerimeterOps())); activePool = new ActivePool(); defaultPool = new DefaultPool(); stabilityPool = new StabilityPool(_permit2); diff --git a/contracts/TestContracts/ExitFeeControllerMock.sol b/contracts/TestContracts/ExitFeeControllerMock.sol index 2d54de0..bbef20c 100644 --- a/contracts/TestContracts/ExitFeeControllerMock.sol +++ b/contracts/TestContracts/ExitFeeControllerMock.sol @@ -28,6 +28,16 @@ contract ExitFeeControllerMock { uint256 public forcedFeeAmount; uint256 public forcedNetAmount; + // --- Delay (security-perimeter) knobs --- + bool public perimeterEnabled; // maps to securityPerimeterEnabled + uint32 public delaySeconds; // returned as `d` when the perimeter charges a delay + bool public delayRevert; // when true, quoteExitDelayFor reverts → exercises the hook's FAIL-CLOSED leg + // Optional passthrough override so a test can force effOrig/effOwner != raw + // (Zero has no passthrough in production, but the fail-closed identity + // threading is still asserted). + bool public overridePassthrough; + address public forcedEffActor; + function configure( bool _active, uint16 _rateBps, @@ -57,6 +67,42 @@ contract ExitFeeControllerMock { forcedNetAmount = _net; } + // --- Delay configuration --- + + function configureDelay(bool _enabled, uint32 _delaySeconds) external { + perimeterEnabled = _enabled; + delaySeconds = _delaySeconds; + } + + function setDelayRevert(bool _v) external { + delayRevert = _v; + } + + function setForcedPassthrough(bool _on, address _effActor) external { + overridePassthrough = _on; + forcedEffActor = _effActor; + } + + /// @dev Single hook entry. Short-circuits the kill switch FIRST: + /// a disabled perimeter returns (0, raw, owner) — pay direct. Otherwise + /// returns the configured delay and (optionally forced) effective actors. + function quoteExitDelayFor( + address rawOriginator, + address owner, + address /* receiver */, + bytes32 /* surfaceId */, + address /* subProduct */ + ) external view returns (uint32 d, address effOrig, address effOwner) { + require(!delayRevert, "EFCMock: forced delay revert"); + if (!perimeterEnabled) { + return (0, rawOriginator, owner); + } + if (overridePassthrough) { + return (delaySeconds, forcedEffActor, forcedEffActor); + } + return (delaySeconds, rawOriginator, owner); + } + function quoteExitFee( bytes32, address, diff --git a/contracts/TestContracts/FunctionCaller.sol b/contracts/TestContracts/FunctionCaller.sol index 91d8188..988ae3b 100644 --- a/contracts/TestContracts/FunctionCaller.sol +++ b/contracts/TestContracts/FunctionCaller.sol @@ -38,10 +38,10 @@ contract FunctionCaller { // --- Non-view wrapper functions used for calculating gas --- - function troveManager_getCurrentICR(address _address, uint256 _price) - external - returns (uint256) - { + function troveManager_getCurrentICR( + address _address, + uint256 _price + ) external returns (uint256) { return troveManager.getCurrentICR(_address, _price); } diff --git a/contracts/TestContracts/LiquityMathTester.sol b/contracts/TestContracts/LiquityMathTester.sol index 56983dd..c401ba7 100644 --- a/contracts/TestContracts/LiquityMathTester.sol +++ b/contracts/TestContracts/LiquityMathTester.sol @@ -7,7 +7,6 @@ import "../Dependencies/LiquityMath.sol"; /* Tester contract for math functions in Math.sol library. */ contract LiquityMathTester { - function callMax(uint _a, uint _b) external pure returns (uint) { return LiquityMath._max(_a, _b); } diff --git a/contracts/TestContracts/MockBalanceRedirectPresale.sol b/contracts/TestContracts/MockBalanceRedirectPresale.sol index 4a9e597..1aca0ae 100644 --- a/contracts/TestContracts/MockBalanceRedirectPresale.sol +++ b/contracts/TestContracts/MockBalanceRedirectPresale.sol @@ -2,9 +2,7 @@ pragma solidity 0.6.11; - -contract MockBalanceRedirectPresale { - +contract MockBalanceRedirectPresale { bool public isClosed; function closePresale() public { @@ -14,4 +12,4 @@ contract MockBalanceRedirectPresale { function openPresale() public { isClosed = false; } -} \ No newline at end of file +} diff --git a/contracts/TestContracts/MockExitDelayQueue.sol b/contracts/TestContracts/MockExitDelayQueue.sol new file mode 100644 index 0000000..d51b12f --- /dev/null +++ b/contracts/TestContracts/MockExitDelayQueue.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.11; +pragma experimental ABIEncoderV2; + +import "../Interfaces/perimeter/IExitDelayQueueHook.sol"; + +/// @title MockExitDelayQueue +/// @notice Minimal test double for the real 0.8.20 `ExitDelayQueue`, implemented +/// at 0.6.11 so the zero-contracts hardhat suites can deploy it and wire +/// it behind `BorrowerOperations` (the registered allowed source). It +/// mirrors ONLY the behaviour the Zero borrower hook depends on: +/// - an unconditional native `receive()` that accepts RBTC from +/// anyone with no sender gate; +/// - `recordReceivedNativeExit` (`onlyAllowedSource`), which narrows to +/// uint128, enforces the per-request delay floor, proves receipt by +/// measured-delta (surplus `>= amount`, credit EXACTLY `amount` — +/// ), stamps `unlockAt = now + delaySeconds`, and emits +/// `ExitQueued`; +/// - `executeExit`, which pays the immutable receiver after `unlockAt` +/// iff `msg.sender ∈ {originator, owner}` (receiver is NOT an executor) +/// and none of {originator, owner, receiver} is blocked; +/// - a minimal `freeze`/`unfreeze` block model so the fail-closed / +/// block-trap regressions can be exercised. +/// The three ERC20 / value-carrying ingress fns are present for interface +/// completeness but revert (the Zero surface is native-only). This is +/// deliberately NOT the full security model — the real queue's recovery +/// legs and per-request index are covered by the perimeter Foundry suite. +contract MockExitDelayQueue is IExitDelayQueueHook { + struct Req { + uint128 amount; + uint64 createdAt; + uint64 unlockAt; + address originator; + address owner; + address receiver; + address token; // address(0) = native + bytes32 surfaceId; + address subProduct; + bool executed; + } + + uint32 public minimumDelaySeconds; + uint256 public lastRequestId; + mapping(uint256 => Req) internal _requests; + mapping(address => bool) public allowedSource; + mapping(address => bool) public blocked; + // token => sum of Queued amounts (backing). address(0) = native. + mapping(address => uint256) public totalEscrowed; + + event ExitQueued( + uint256 indexed id, + address indexed originator, + address indexed owner, + address receiver, + address token, + uint128 amount, + uint64 unlockAt, + bytes32 surfaceId, + address subProduct + ); + event ExitExecuted( + uint256 indexed id, + address indexed receiver, + address token, + uint128 amount + ); + + constructor(uint32 _minDelay) public { + minimumDelaySeconds = _minDelay; + } + + /// @dev Unconditional native receive() — accepts RBTC from anyone. + receive() external payable {} + + function setAllowedSource(address src, bool ok) external { + allowedSource[src] = ok; + } + + function freeze(address a) external { + blocked[a] = true; + } + + function unfreeze(address a) external { + blocked[a] = false; + } + + modifier onlyAllowedSource() { + require(allowedSource[msg.sender], "MockQueue: unregistered source"); + _; + } + + function getRequest(uint256 id) external view returns (Req memory) { + return _requests[id]; + } + + // ── Native measured-receipt ingress (the ONLY path Zero uses) ───────────── + + function recordReceivedNativeExit( + uint128 amount, + uint32 delaySeconds, + bytes32 surfaceId, + address subProduct, + address effOrig, + address effOwner, + address receiver + ) external override onlyAllowedSource returns (uint256 id) { + require(amount > 0, "MockQueue: zero amount"); + require(delaySeconds >= minimumDelaySeconds, "MockQueue: delay below floor"); + // measured-receipt: the native RBTC was pushed to receive() first; the + // non-backing surplus must cover `amount`, and we credit EXACTLY `amount` + // A stray donation only raises the surplus and cannot brick the record. + uint256 surplus = address(this).balance - totalEscrowed[address(0)]; + require(surplus >= amount, "MockQueue: received amount mismatch"); + totalEscrowed[address(0)] += amount; + + id = ++lastRequestId; + Req storage r = _requests[id]; + r.amount = amount; + r.createdAt = uint64(block.timestamp); + r.unlockAt = uint64(block.timestamp + delaySeconds); + r.originator = effOrig; + r.owner = effOwner; + r.receiver = receiver; + r.token = address(0); + r.surfaceId = surfaceId; + r.subProduct = subProduct; + + emit ExitQueued( + id, + effOrig, + effOwner, + receiver, + address(0), + amount, + r.unlockAt, + surfaceId, + subProduct + ); + } + + // ── Execution (subset) ──────────────────────────────────────────────────── + + function executeExit(uint256 id) external { + Req storage r = _requests[id]; + require(r.amount > 0 && !r.executed, "MockQueue: not queued"); + require(block.timestamp >= r.unlockAt, "MockQueue: not unlocked"); + require(msg.sender == r.originator || msg.sender == r.owner, "MockQueue: not executor"); + require( + !blocked[r.originator] && !blocked[r.owner] && !blocked[r.receiver], + "MockQueue: actor blocked" + ); + + r.executed = true; + totalEscrowed[r.token] -= r.amount; + uint128 amount = r.amount; + address payable receiver = address(uint160(r.receiver)); + + (bool ok, ) = receiver.call{ value: amount }(""); + require(ok, "MockQueue: payout failed"); + emit ExitExecuted(id, receiver, r.token, amount); + } + + // ── Interface completeness (Zero is native-only; these are unused) ──────── + + function recordERC20Exit( + address, + uint128, + uint32, + bytes32, + address, + address, + address, + address, + bool + ) external override returns (uint256) { + revert("MockQueue: erc20 unsupported"); + } + + function recordReceivedERC20Exit( + address, + uint128, + uint32, + bytes32, + address, + address, + address, + address + ) external override returns (uint256) { + revert("MockQueue: erc20 unsupported"); + } + + function recordNativeExit( + uint128, + uint32, + bytes32, + address, + address, + address, + address + ) external payable override returns (uint256) { + revert("MockQueue: value-carrying unsupported"); + } +} diff --git a/contracts/TestContracts/MockFeeSharingCollector.sol b/contracts/TestContracts/MockFeeSharingCollector.sol index f026a72..748b0f9 100644 --- a/contracts/TestContracts/MockFeeSharingCollector.sol +++ b/contracts/TestContracts/MockFeeSharingCollector.sol @@ -5,15 +5,15 @@ pragma solidity 0.6.11; import "../ZERO/ZEROToken.sol"; interface MockIFeeSharingCollector { - function transferTokens(address _token, uint96 _amount) external; + function transferTokens(address _token, uint96 _amount) external; } /// @dev Simple contract that will receive ZERO tokens issued to the SOV stakers. contract MockFeeSharingCollector is MockIFeeSharingCollector { - function transferTokens(address _token, uint96 _amount) override external { - /// Just a fake function to receive the tokens - ZEROToken(_token).transferFrom(msg.sender, address(this), _amount); - } + function transferTokens(address _token, uint96 _amount) external override { + /// Just a fake function to receive the tokens + ZEROToken(_token).transferFrom(msg.sender, address(this), _amount); + } - function transferRBTC() external payable {} + function transferRBTC() external payable {} } diff --git a/contracts/TestContracts/NonPayable.sol b/contracts/TestContracts/NonPayable.sol index cc22d77..c749325 100644 --- a/contracts/TestContracts/NonPayable.sol +++ b/contracts/TestContracts/NonPayable.sol @@ -4,7 +4,6 @@ pragma solidity 0.6.11; //import "../Dependencies/console.sol"; - contract NonPayable { bool isPayable; diff --git a/contracts/TestContracts/PerimeterRawCatcher.sol b/contracts/TestContracts/PerimeterRawCatcher.sol new file mode 100644 index 0000000..1b513ec --- /dev/null +++ b/contracts/TestContracts/PerimeterRawCatcher.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.11; + +/// @notice Test helper that performs a low-level call and RETURNS the raw +/// returndata instead of bubbling it, so a test can read the exact +/// revert payload a reverting exit produces — independent of how the +/// node formats its error. +contract PerimeterRawCatcher { + function probe( + address target, + bytes calldata data + ) external payable returns (bool ok, bytes memory ret) { + (ok, ret) = target.call.value(msg.value)(data); + } + + receive() external payable {} +} diff --git a/contracts/TestContracts/PriceFeedSovrynTester.sol b/contracts/TestContracts/PriceFeedSovrynTester.sol index 88d1092..4fce727 100644 --- a/contracts/TestContracts/PriceFeedSovrynTester.sol +++ b/contracts/TestContracts/PriceFeedSovrynTester.sol @@ -6,9 +6,9 @@ import "../Interfaces/IPriceFeedSovryn.sol"; import "../Dependencies/SafeMath.sol"; /* -* PriceFeed placeholder for testnet and development. The price is simply set manually and saved in a state -* variable. The contract does not connect to a live Chainlink price feed. -*/ + * PriceFeed placeholder for testnet and development. The price is simply set manually and saved in a state + * variable. The contract does not connect to a live Chainlink price feed. + */ contract PriceFeedSovrynTester { using SafeMath for uint256; @@ -20,7 +20,10 @@ contract PriceFeedSovrynTester { prices[sourceToken][destToken] = price; } - function queryRate(address sourceToken, address destToken) public view returns(uint256 rate, uint256 precision) { + function queryRate( + address sourceToken, + address destToken + ) public view returns (uint256 rate, uint256 precision) { return (prices[sourceToken][destToken], 1e18); } diff --git a/contracts/TestContracts/PriceFeedTestnet.sol b/contracts/TestContracts/PriceFeedTestnet.sol index ffdb76d..d5a71c1 100644 --- a/contracts/TestContracts/PriceFeedTestnet.sol +++ b/contracts/TestContracts/PriceFeedTestnet.sol @@ -5,11 +5,10 @@ pragma solidity 0.6.11; import "../Interfaces/IPriceFeed.sol"; /* -* PriceFeed placeholder for testnet and development. The price is simply set manually and saved in a state -* variable. The contract does not connect to a live Chainlink price feed. -*/ + * PriceFeed placeholder for testnet and development. The price is simply set manually and saved in a state + * variable. The contract does not connect to a live Chainlink price feed. + */ contract PriceFeedTestnet is IPriceFeed { - uint256 private _price = 200 * 1e18; // --- Functions --- diff --git a/contracts/TestContracts/SelectorRevertingExitDelayQueue.sol b/contracts/TestContracts/SelectorRevertingExitDelayQueue.sol new file mode 100644 index 0000000..194398a --- /dev/null +++ b/contracts/TestContracts/SelectorRevertingExitDelayQueue.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.6.11; +pragma experimental ABIEncoderV2; + +import "../Interfaces/perimeter/IExitDelayQueueHook.sol"; + +/// @title SelectorRevertingExitDelayQueue +/// @notice Test double for the SR1 selector-propagation regression. The +/// REAL `ExitDelayQueue` is Solidity 0.8.20 and its `onlyAllowedSource` +/// guard reverts with the CUSTOM ERROR `UnregisteredSource(address)` — a +/// distinct 4-byte selector the off-chain halt watcher keys on. This +/// mock reproduces that exact revert payload at 0.6.11 +/// (which cannot declare `error` types) by reverting with the raw +/// ABI-encoding `abi.encodeWithSelector(UnregisteredSource.selector, +/// msg.sender)` via inline assembly. +/// +/// The point of the regression: the 0.6.11 `BorrowerOperations` delay +/// hook calls `recordReceivedNativeExit` as a PLAIN external call (it does +/// NOT wrap it in a try/catch or re-`require` with a string reason), so +/// the queue's custom-error selector must BUBBLE UP UNCHANGED out of the +/// reverting trove exit. A test asserts the returndata's leading 4 bytes +/// equal `bytes4(keccak256("UnregisteredSource(address)"))` — proving the +/// distinct halt selector survives the cross-pragma boundary and is not +/// masked by a host-side wrapper. +contract SelectorRevertingExitDelayQueue is IExitDelayQueueHook { + /// bytes4(keccak256("UnregisteredSource(address)")) — evaluated at compile time. + bytes4 public constant UNREGISTERED_SOURCE_SELECTOR = + bytes4(keccak256("UnregisteredSource(address)")); + + /// @dev Unconditional native receive() — the ActivePool push lands here + /// BEFORE the record call, exactly as against the real queue, so the revert + /// under test is the record leg (not a failed push). + receive() external payable {} + + /// @dev Reverts with the raw `UnregisteredSource(msg.sender)` custom-error bytes, + /// byte-identical to what the 0.8.20 queue emits. No string wrapping. + function recordReceivedNativeExit( + uint128, + uint32, + bytes32, + address, + address, + address, + address + ) external override returns (uint256) { + bytes memory err = abi.encodeWithSelector(UNREGISTERED_SOURCE_SELECTOR, msg.sender); + assembly { + revert(add(err, 0x20), mload(err)) + } + } + + // ── Interface completeness (unused by the Zero native path) ─────────────── + + function recordERC20Exit( + address, + uint128, + uint32, + bytes32, + address, + address, + address, + address, + bool + ) external override returns (uint256) { + revert("unsupported"); + } + + function recordReceivedERC20Exit( + address, + uint128, + uint32, + bytes32, + address, + address, + address, + address + ) external override returns (uint256) { + revert("unsupported"); + } + + function recordNativeExit( + uint128, + uint32, + bytes32, + address, + address, + address, + address + ) external payable override returns (uint256) { + revert("unsupported"); + } +} diff --git a/contracts/TestContracts/SortedTrovesTester.sol b/contracts/TestContracts/SortedTrovesTester.sol index 4d75041..142a8cd 100644 --- a/contracts/TestContracts/SortedTrovesTester.sol +++ b/contracts/TestContracts/SortedTrovesTester.sol @@ -4,7 +4,6 @@ pragma solidity 0.6.11; import "../Interfaces/ISortedTroves.sol"; - contract SortedTrovesTester { ISortedTroves sortedTroves; diff --git a/contracts/TestContracts/StabilityPoolTester.sol b/contracts/TestContracts/StabilityPoolTester.sol index 98bd49a..3bc0781 100644 --- a/contracts/TestContracts/StabilityPoolTester.sol +++ b/contracts/TestContracts/StabilityPoolTester.sol @@ -6,10 +6,9 @@ pragma experimental ABIEncoderV2; import "../StabilityPool.sol"; contract StabilityPoolTester is StabilityPool { - /** Constructor */ constructor(address _permit2) public StabilityPool(_permit2) {} - + function unprotectedPayable() external payable { ETH = ETH.add(msg.value); } diff --git a/contracts/TestContracts/UpgradableProxyTester.sol b/contracts/TestContracts/UpgradableProxyTester.sol index 9c1c287..146142a 100644 --- a/contracts/TestContracts/UpgradableProxyTester.sol +++ b/contracts/TestContracts/UpgradableProxyTester.sol @@ -1,14 +1,13 @@ - // SPDX-License-Identifier: MIT pragma solidity 0.6.11; import "../Proxy/UpgradableProxy.sol"; + contract Storage { uint someVar; } contract ProxiableContract is Storage { - function getSomeVar() public view returns (uint) { return someVar; } @@ -23,7 +22,6 @@ contract Storage2 { } contract ProxiableContract2 is ProxiableContract, Storage2 { - function getAnotherVar() public view returns (uint) { return anotherVar; } diff --git a/contracts/TestContracts/WRBTCTokenTester.sol b/contracts/TestContracts/WRBTCTokenTester.sol index a878dc1..3e8d684 100644 --- a/contracts/TestContracts/WRBTCTokenTester.sol +++ b/contracts/TestContracts/WRBTCTokenTester.sol @@ -16,88 +16,84 @@ pragma solidity 0.6.11; contract WRBTCTokenTester { - string public name = "Wrapped BTC"; - string public symbol = "WRBTC"; - uint8 public decimals = 18; - - event Approval(address indexed src, address indexed guy, uint256 wad); - event Transfer(address indexed src, address indexed dst, uint256 wad); - event Deposit(address indexed dst, uint256 wad); - event Withdrawal(address indexed src, uint256 wad); - - mapping(address => uint256) public balanceOf; - mapping(address => mapping(address => uint256)) public allowance; - - fallback() external payable { - deposit(); - } - - function deposit() public payable { - balanceOf[msg.sender] += msg.value; - emit Deposit(msg.sender, msg.value); - } - - function withdraw(uint256 wad) public { - require(balanceOf[msg.sender] >= wad); - balanceOf[msg.sender] -= wad; - msg.sender.transfer(wad); - emit Withdrawal(msg.sender, wad); - } - - function totalSupply() public view returns (uint256) { - return address(this).balance; - } - - function approve(address guy, uint256 wad) public returns (bool) { - allowance[msg.sender][guy] = wad; - emit Approval(msg.sender, guy, wad); - return true; - } - - function transfer(address dst, uint256 wad) public returns (bool) { - return transferFrom(msg.sender, dst, wad); - } - - function transferFrom( - address src, - address dst, - uint256 wad - ) public returns (bool) { - require(balanceOf[src] >= wad); - - if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { - require(allowance[src][msg.sender] >= wad); - allowance[src][msg.sender] -= wad; - } - - balanceOf[src] -= wad; - balanceOf[dst] += wad; - - emit Transfer(src, dst, wad); - - return true; - } - - /** - * added for local swap implementation - * */ - function mint(address _to, uint256 _value) public { - require(_to != address(0), "no burn allowed"); - balanceOf[_to] = balanceOf[_to] + _value; - emit Transfer(address(0), _to, _value); - } - - /** - * added for local swap implementation - * */ - function burn(address _who, uint256 _value) public { - require(_value <= balanceOf[_who], "balance too low"); - // no need to require _value <= totalSupply, since that would imply the - // sender's balance is greater than the totalSupply, which *should* be an assertion failure - - balanceOf[_who] = balanceOf[_who] - _value; - emit Transfer(_who, address(0), _value); - } + string public name = "Wrapped BTC"; + string public symbol = "WRBTC"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + fallback() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + msg.sender.transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } + + /** + * added for local swap implementation + * */ + function mint(address _to, uint256 _value) public { + require(_to != address(0), "no burn allowed"); + balanceOf[_to] = balanceOf[_to] + _value; + emit Transfer(address(0), _to, _value); + } + + /** + * added for local swap implementation + * */ + function burn(address _who, uint256 _value) public { + require(_value <= balanceOf[_who], "balance too low"); + // no need to require _value <= totalSupply, since that would imply the + // sender's balance is greater than the totalSupply, which *should* be an assertion failure + + balanceOf[_who] = balanceOf[_who] - _value; + emit Transfer(_who, address(0), _value); + } } /* diff --git a/contracts/TestContracts/ZEROStakingTester.sol b/contracts/TestContracts/ZEROStakingTester.sol index db71335..10da67a 100644 --- a/contracts/TestContracts/ZEROStakingTester.sol +++ b/contracts/TestContracts/ZEROStakingTester.sol @@ -4,7 +4,6 @@ pragma solidity 0.6.11; import "../ZERO/ZEROStaking.sol"; - contract ZEROStakingTester is ZEROStaking { function requireCallerIsFeeDistributor() external view { _requireCallerIsFeeDistributor(); diff --git a/contracts/TestContracts/ZEROTokenTester.sol b/contracts/TestContracts/ZEROTokenTester.sol index 009c12a..2511178 100644 --- a/contracts/TestContracts/ZEROTokenTester.sol +++ b/contracts/TestContracts/ZEROTokenTester.sol @@ -5,20 +5,13 @@ pragma solidity 0.6.11; import "../ZERO/ZEROToken.sol"; contract ZEROTokenTester is ZEROToken { - constructor - ( + constructor( address _zeroStakingAddress, address _marketMakerAddress, address _presaleAddress - ) - public - { - initialize( - _zeroStakingAddress, - _marketMakerAddress, - _presaleAddress - ); - } + ) public { + initialize(_zeroStakingAddress, _marketMakerAddress, _presaleAddress); + } function unprotectedMint(address account, uint256 amount) external { // No check for the caller here @@ -28,15 +21,23 @@ contract ZEROTokenTester is ZEROToken { function unprotectedSendToZEROStaking(address _sender, uint256 _amount) external { // No check for the caller here - + _transfer(_sender, zeroStakingAddress, _amount); } - function callInternalApprove(address owner, address spender, uint256 amount) external returns (bool) { + function callInternalApprove( + address owner, + address spender, + uint256 amount + ) external returns (bool) { _approve(owner, spender, amount); } - function callInternalTransfer(address sender, address recipient, uint256 amount) external returns (bool) { + function callInternalTransfer( + address sender, + address recipient, + uint256 amount + ) external returns (bool) { _transfer(sender, recipient, amount); } @@ -46,4 +47,4 @@ contract ZEROTokenTester is ZEROToken { chainID := chainid() } } -} \ No newline at end of file +} diff --git a/contracts/TestContracts/ZUSDTokenCaller.sol b/contracts/TestContracts/ZUSDTokenCaller.sol index a6340e1..8993d10 100644 --- a/contracts/TestContracts/ZUSDTokenCaller.sol +++ b/contracts/TestContracts/ZUSDTokenCaller.sol @@ -19,11 +19,15 @@ contract ZUSDTokenCaller { ZUSD.burn(_account, _amount); } - function zusdSendToPool(address _sender, address _poolAddress, uint256 _amount) external { + function zusdSendToPool(address _sender, address _poolAddress, uint256 _amount) external { ZUSD.sendToPool(_sender, _poolAddress, _amount); } - function zusdReturnFromPool(address _poolAddress, address _receiver, uint256 _amount ) external { + function zusdReturnFromPool( + address _poolAddress, + address _receiver, + uint256 _amount + ) external { ZUSD.returnFromPool(_poolAddress, _receiver, _amount); } } diff --git a/contracts/TestContracts/ZUSDTokenTester.sol b/contracts/TestContracts/ZUSDTokenTester.sol index d9a7acb..537f211 100644 --- a/contracts/TestContracts/ZUSDTokenTester.sol +++ b/contracts/TestContracts/ZUSDTokenTester.sol @@ -5,15 +5,14 @@ pragma solidity 0.6.11; import "../ZUSDToken.sol"; contract ZUSDTokenTester is ZUSDToken { - - constructor( + constructor( address _troveManagerAddress, address _stabilityPoolAddress, address _borrowerOperationsAddress - ) public { + ) public { initialize(_troveManagerAddress, _stabilityPoolAddress, _borrowerOperationsAddress); } - + function unprotectedMint(address _account, uint256 _amount) external { // No check on caller here @@ -22,23 +21,35 @@ contract ZUSDTokenTester is ZUSDToken { function unprotectedBurn(address _account, uint _amount) external { // No check on caller here - + _burn(_account, _amount); } - function unprotectedSendToPool(address _sender, address _poolAddress, uint256 _amount) external { + function unprotectedSendToPool( + address _sender, + address _poolAddress, + uint256 _amount + ) external { // No check on caller here _transfer(_sender, _poolAddress, _amount); } - function unprotectedReturnFromPool(address _poolAddress, address _receiver, uint256 _amount ) external { + function unprotectedReturnFromPool( + address _poolAddress, + address _receiver, + uint256 _amount + ) external { // No check on caller here _transfer(_poolAddress, _receiver, _amount); } - function callInternalApprove(address owner, address spender, uint256 amount) external returns (bool) { + function callInternalApprove( + address owner, + address spender, + uint256 amount + ) external returns (bool) { _approve(owner, spender, amount); } @@ -49,16 +60,31 @@ contract ZUSDTokenTester is ZUSDToken { } } - function getDigest(address owner, address spender, uint amount, uint nonce, uint deadline) external view returns (bytes32) { - return keccak256(abi.encodePacked( - uint16(0x1901), - domainSeparator(), - keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, amount, nonce, deadline)) - ) - ); + function getDigest( + address owner, + address spender, + uint amount, + uint nonce, + uint deadline + ) external view returns (bytes32) { + return + keccak256( + abi.encodePacked( + uint16(0x1901), + domainSeparator(), + keccak256( + abi.encode(_PERMIT_TYPEHASH, owner, spender, amount, nonce, deadline) + ) + ) + ); } - function recoverAddress(bytes32 digest, uint8 v, bytes32 r, bytes32 s) external pure returns (address) { + function recoverAddress( + bytes32 digest, + uint8 v, + bytes32 r, + bytes32 s + ) external pure returns (address) { return ecrecover(digest, v, r, s); } } diff --git a/contracts/TroveManager.sol b/contracts/TroveManager.sol index cfcc2f0..63bc49c 100644 --- a/contracts/TroveManager.sol +++ b/contracts/TroveManager.sol @@ -38,7 +38,10 @@ contract TroveManager is TroveManagerBase, CheckContract, ITroveManager { event ZEROStakingAddressChanged(address _zeroStakingAddress); ///@param _bootstrapPeriod During bootsrap period redemptions are not allowed - constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) { + constructor( + uint256 _bootstrapPeriod, + address _permit2 + ) public TroveManagerBase(_bootstrapPeriod) { permit2 = IPermit2(_permit2); } diff --git a/contracts/ZERO/CommunityIssuance.sol b/contracts/ZERO/CommunityIssuance.sol index 75e1328..fd0b313 100644 --- a/contracts/ZERO/CommunityIssuance.sol +++ b/contracts/ZERO/CommunityIssuance.sol @@ -148,7 +148,9 @@ contract CommunityIssuance is */ function _issueSOV(uint256 _totalZUSDDeposits) internal returns (uint256) { uint256 timePassedSinceLastIssuance = (block.timestamp.sub(lastIssuanceTime)); - uint256 issuance = _getZUSDToSOV(_totalZUSDDeposits.mul(APR).mul(timePassedSinceLastIssuance).div(365 days).div(MAX_BPS)); + uint256 issuance = _getZUSDToSOV( + _totalZUSDDeposits.mul(APR).mul(timePassedSinceLastIssuance).div(365 days).div(MAX_BPS) + ); totalSOVIssued = totalSOVIssued + issuance; lastIssuanceTime = block.timestamp; diff --git a/contracts/ZERO/CommunityIssuanceStorage.sol b/contracts/ZERO/CommunityIssuanceStorage.sol index 7d2c3a5..87e1fcd 100644 --- a/contracts/ZERO/CommunityIssuanceStorage.sol +++ b/contracts/ZERO/CommunityIssuanceStorage.sol @@ -10,7 +10,7 @@ import "../Dependencies/Initializable.sol"; contract CommunityIssuanceStorage is Ownable, Initializable { // --- Data --- - string constant public NAME = "CommunityIssuance"; + string public constant NAME = "CommunityIssuance"; uint256 constant MAX_BPS = 10000; diff --git a/contracts/ZERO/ZEROStaking.sol b/contracts/ZERO/ZEROStaking.sol index 9a8b4dc..885ff5c 100644 --- a/contracts/ZERO/ZEROStaking.sol +++ b/contracts/ZERO/ZEROStaking.sol @@ -187,7 +187,7 @@ contract ZEROStaking is ZEROStakingStorage, IZEROStaking, CheckContract, BaseMat function _sendETHGainToUser(uint256 ETHGain) internal { emit EtherSent(msg.sender, ETHGain); - (bool success, ) = msg.sender.call{value: ETHGain}(""); + (bool success, ) = msg.sender.call{ value: ETHGain }(""); require(success, "ZEROStaking: Failed to send accumulated ETHGain"); } diff --git a/contracts/ZERO/ZEROStakingStorage.sol b/contracts/ZERO/ZEROStakingStorage.sol index 9a79294..c5491d4 100644 --- a/contracts/ZERO/ZEROStakingStorage.sol +++ b/contracts/ZERO/ZEROStakingStorage.sol @@ -8,26 +8,25 @@ import "../Interfaces/IZUSDToken.sol"; contract ZEROStakingStorage is Ownable { // --- Data --- - string constant public NAME = "ZEROStaking"; + string public constant NAME = "ZEROStaking"; - mapping( address => uint) public stakes; + mapping(address => uint) public stakes; uint public totalZEROStaked; - uint public F_ETH; // Running sum of ETH fees per-ZERO-staked + uint public F_ETH; // Running sum of ETH fees per-ZERO-staked uint public F_ZUSD; // Running sum of ZERO fees per-ZERO-staked // User snapshots of F_ETH and F_ZUSD, taken at the point at which their latest deposit was made - mapping (address => Snapshot) public snapshots; + mapping(address => Snapshot) public snapshots; struct Snapshot { uint F_ETH_Snapshot; uint F_ZUSD_Snapshot; } - + IZEROToken public zeroToken; IZUSDToken public zusdToken; address public feeDistributorAddress; address public activePoolAddress; - } diff --git a/contracts/ZERO/ZEROToken.sol b/contracts/ZERO/ZEROToken.sol index 02c46cc..6f8ec58 100644 --- a/contracts/ZERO/ZEROToken.sol +++ b/contracts/ZERO/ZEROToken.sol @@ -119,20 +119,18 @@ contract ZEROToken is ZEROTokenStorage, CheckContract, IZEROToken { return true; } - function increaseAllowance(address spender, uint256 addedValue) - external - override - returns (bool) - { + function increaseAllowance( + address spender, + uint256 addedValue + ) external override returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } - function decreaseAllowance(address spender, uint256 subtractedValue) - external - override - returns (bool) - { + function decreaseAllowance( + address spender, + uint256 subtractedValue + ) external override returns (bool) { _approve( msg.sender, spender, @@ -174,7 +172,14 @@ contract ZEROToken is ZEROTokenStorage, CheckContract, IZEROToken { "\x19\x01", domainSeparator(), keccak256( - abi.encode(_PERMIT_TYPEHASH, owner, spender, amount, _nonces[owner]++, deadline) + abi.encode( + _PERMIT_TYPEHASH, + owner, + spender, + amount, + _nonces[owner]++, + deadline + ) ) ) ); @@ -204,17 +209,16 @@ contract ZEROToken is ZEROTokenStorage, CheckContract, IZEROToken { return keccak256(abi.encode(typeHash, name, version, _chainID(), address(this))); } - function _transfer( - address sender, - address recipient, - uint256 amount - ) internal { + function _transfer(address sender, address recipient, uint256 amount) internal { return; // disable the func call - ZEROToken is not used in beta require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); require(presale.isClosed(), "Presale is not over yet"); - _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[sender] = _balances[sender].sub( + amount, + "ERC20: transfer amount exceeds balance" + ); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); @@ -239,11 +243,7 @@ contract ZEROToken is ZEROTokenStorage, CheckContract, IZEROToken { emit Transfer(account, address(0), amount); } - function _approve( - address owner, - address spender, - uint256 amount - ) internal { + function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); diff --git a/contracts/ZERO/ZEROTokenStorage.sol b/contracts/ZERO/ZEROTokenStorage.sol index 7f707c9..9a15995 100644 --- a/contracts/ZERO/ZEROTokenStorage.sol +++ b/contracts/ZERO/ZEROTokenStorage.sol @@ -8,21 +8,23 @@ import "../Dependencies/Initializable.sol"; contract ZEROTokenStorage is Initializable { // --- ERC20 Data --- - string constant internal _NAME = "ZERO"; - string constant internal _SYMBOL = "ZERO"; - string constant internal _VERSION = "1"; - uint8 constant internal _DECIMALS = 18; + string internal constant _NAME = "ZERO"; + string internal constant _SYMBOL = "ZERO"; + string internal constant _VERSION = "1"; + uint8 internal constant _DECIMALS = 18; - mapping (address => uint256) internal _balances; - mapping (address => mapping (address => uint256)) internal _allowances; + mapping(address => uint256) internal _balances; + mapping(address => mapping(address => uint256)) internal _allowances; uint internal _totalSupply; // --- EIP 2612 Data --- // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 internal constant _PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + bytes32 internal constant _PERMIT_TYPEHASH = + 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); - bytes32 internal constant _TYPE_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + bytes32 internal constant _TYPE_HASH = + 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. @@ -31,20 +33,19 @@ contract ZEROTokenStorage is Initializable { bytes32 internal _HASHED_NAME; bytes32 internal _HASHED_VERSION; - - mapping (address => uint256) internal _nonces; + + mapping(address => uint256) internal _nonces; // --- ZEROToken specific data --- - uint public constant ONE_YEAR_IN_SECONDS = 31536000; // 60 * 60 * 24 * 365 + uint public constant ONE_YEAR_IN_SECONDS = 31536000; // 60 * 60 * 24 * 365 // uint for use with SafeMath - uint internal constant _1_MILLION = 1e24; // 1e6 * 1e18 = 1e24 + uint internal constant _1_MILLION = 1e24; // 1e6 * 1e18 = 1e24 uint internal deploymentStartTime; address public zeroStakingAddress; address public marketMakerAddress; IBalanceRedirectPresale public presale; - } diff --git a/contracts/ZUSDToken.sol b/contracts/ZUSDToken.sol index b56e1b6..7ebcfd8 100644 --- a/contracts/ZUSDToken.sol +++ b/contracts/ZUSDToken.sol @@ -81,11 +81,7 @@ contract ZUSDToken is ZUSDTokenStorage, CheckContract, IZUSDToken, Ownable { _burn(_account, _amount); } - function sendToPool( - address _sender, - address _poolAddress, - uint256 _amount - ) external override { + function sendToPool(address _sender, address _poolAddress, uint256 _amount) external override { _requireCallerIsStabilityPool(); _transfer(_sender, _poolAddress, _amount); } @@ -139,20 +135,18 @@ contract ZUSDToken is ZUSDTokenStorage, CheckContract, IZUSDToken, Ownable { return true; } - function increaseAllowance(address spender, uint256 addedValue) - external - override - returns (bool) - { + function increaseAllowance( + address spender, + uint256 addedValue + ) external override returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } - function decreaseAllowance(address spender, uint256 subtractedValue) - external - override - returns (bool) - { + function decreaseAllowance( + address spender, + uint256 subtractedValue + ) external override returns (bool) { _approve( msg.sender, spender, @@ -229,11 +223,7 @@ contract ZUSDToken is ZUSDTokenStorage, CheckContract, IZUSDToken, Ownable { // --- Internal operations --- // Warning: sanity checks (for sender and recipient) should have been done before calling these internal functions - function _transfer( - address sender, - address recipient, - uint256 amount - ) internal { + function _transfer(address sender, address recipient, uint256 amount) internal { assert(sender != address(0)); assert(recipient != address(0)); @@ -261,11 +251,7 @@ contract ZUSDToken is ZUSDTokenStorage, CheckContract, IZUSDToken, Ownable { emit Transfer(account, address(0), amount); } - function _approve( - address owner, - address spender, - uint256 amount - ) internal { + function _approve(address owner, address spender, uint256 amount) internal { assert(owner != address(0)); assert(spender != address(0)); diff --git a/deployment/deploy/9-BorrowerOperationsPerimeterOps.ts b/deployment/deploy/9-BorrowerOperationsPerimeterOps.ts new file mode 100644 index 0000000..2b9ea93 --- /dev/null +++ b/deployment/deploy/9-BorrowerOperationsPerimeterOps.ts @@ -0,0 +1,68 @@ +import { DeployFunction } from "hardhat-deploy/types"; +import { getContractNameFromScriptFileName } from "../../scripts/helpers/utils"; +const path = require("path"); +import Logs from "node-logs"; +const logger = new Logs().showInConsole(true); +import * as helpers from "../../scripts/helpers/helpers"; + +const deploymentName = getContractNameFromScriptFileName(path.basename(__filename)); + +const func: DeployFunction = async (hre) => { + const { + getNamedAccounts, + ethers, + deployments: { get, deploy, log, execute }, + network, + } = hre; + + const { deployer } = await getNamedAccounts(); + const borrowerOperations = await ethers.getContract("BorrowerOperations"); + + const tx = await deploy(deploymentName, { + from: deployer, + args: [], + log: true, + }); + + const prevImpl = await borrowerOperations.perimeterOps(); + log(`Current ${deploymentName}: ${prevImpl}`); + + if (tx.newlyDeployed || tx.address != prevImpl) { + if (tx.address != prevImpl) { + logger.information( + `${deploymentName} is reused. However it was not set in the BorrowerOperations contract as perimeterOps yet.` + ); + } + if (network.tags.testnet) { + console.log("testnet"); + logger.information( + `Initiating multisig tx to set BorrowerOperationsPerimeterOps in BorrowerOperations....` + ); + const deployment = await get(deploymentName); + const multisigAddress = (await get("MultiSigWallet")).address; + const data = borrowerOperations.interface.encodeFunctionData("setPerimeterOps", [ + deployment.address, + ]); + + await helpers.sendWithMultisig( + hre, + multisigAddress, + borrowerOperations.target.toString(), + data, + deployer + ); + } else if (network.tags.mainnet) { + // create SIP message + console.log("mainnet"); + logger.info(`>>> Add ${deploymentName} address ${tx.address} update to a SIP`); + } else { + // just set the hook directly + console.log("else!"); + await execute("BorrowerOperations", { from: deployer }, "setPerimeterOps", tx.address); + } + } +}; + +func.tags = [deploymentName]; +func.dependencies = ["BorrowerOperations"]; +export default func; diff --git a/hardhat.config.ts b/hardhat.config.ts index 90d976d..43bd114 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -163,9 +163,12 @@ const config: HardhatUserConfig = { }, // Emit per-contract storageLayout so the Perimeter storage-layout // zero-diff regression (tests-perimeter/StorageLayout.zerodiff.test.js) - // can assert the surplus-claim fee hook adds NO state to the + // can assert that neither the surplus-claim fee hook nor the + // security-perimeter delay reroute adds state to the // upgradeable BorrowerOperations / CollSurplusPool proxies or - // ActivePool. Additive solc output; does not affect bytecode. + // ActivePool (controller/queue pointers live in EIP-1967 + // unstructured slots). Additive solc output; does not affect + // bytecode. outputSelection: { "*": { "*": ["storageLayout"], diff --git a/tests-perimeter/StorageLayout.zerodiff.test.js b/tests-perimeter/StorageLayout.zerodiff.test.js index ea91a5b..817f149 100644 --- a/tests-perimeter/StorageLayout.zerodiff.test.js +++ b/tests-perimeter/StorageLayout.zerodiff.test.js @@ -1,28 +1,30 @@ -// Perimeter security perimeter — storage-layout ZERO-DIFF regression. +// Perimeter security perimeter — storage-layout upgrade-safety regression. // -// The Zero surplus-claim exit-fee hook adds NO storage to any deployed -// upgradeable contract: the surface id is a constant, the exit-fee controller -// pointer lives in an EIP-1967-style unstructured slot, and the hook declares -// no new state variables on the BorrowerOperations or CollSurplusPool proxies. -// That is true BY CONSTRUCTION today — but nothing GUARDS a future edit from -// appending a `uint256` to the proxy and silently corrupting every live -// trove's storage on the next upgrade. +// The perimeter surfaces are storage-frugal by construction: the surface ids are +// constants and the exit-fee controller / ExitDelayQueue pointers live in +// EIP-1967-style unstructured slots (keccak256("sovryn.perimeter*") - 1), so they +// occupy no regular-storage slot. The one exception is BorrowerOperations, which +// holds the perimeter settlement hook address in a plain, APPENDED slot — +// mirroring TroveManager's `troveManagerRedeemOps`. // -// This test is that guard. It compares the current, normalized solc -// `storageLayout` of BorrowerOperations, CollSurplusPool, and ActivePool -// against a committed baseline and FAILS on any label/slot/offset/type -// difference. The Perimeter lending side carries an equivalent Hardhat guard over -// its own upgradeable contracts. +// This test guards both properties against a future edit that would silently +// corrupt every live trove's storage on the next upgrade. It compares the +// current, normalized solc `storageLayout` against a committed baseline under a +// per-target policy: // -// SCOPE OF THE BASELINE (be precise about what this proves): the committed -// baseline was captured at `sovryn-perimeter-fee @ b6584a6`, a tree that ALREADY -// contains the borrower-exit hook (`_sendCollWithExitFee`, the unstructured -// controller slot, the surface-id constants). So this guard proves the -// SURPLUS-CLAIM hook appended no state, and forbids any future append to all -// three contracts. It does NOT independently re-prove the borrower-exit hook's -// zero-diff — that holds by construction (constants + an EIP-1967-style slot, -// neither of which occupies a regular-storage slot) and is reviewable in the -// contract source, but it is not what this baseline compares against. +// ZERO_DIFF — any label/slot/offset/type difference fails (ActivePool, +// CollSurplusPool: hooked but stateless). +// APPEND_ONLY — the baseline prefix must be byte-identical AND every added +// entry must occupy a slot strictly beyond the baseline's last +// slot; reordering, retyping, resizing or inserting fails +// (BorrowerOperations). +// +// SCOPE OF THE BASELINE: captured at `sovryn-perimeter-fee @ b6584a6`, a tree that +// ALREADY contains the borrower-exit fee hook. So this guard proves the +// surplus-claim hook and the exit-delay hooks appended nothing beyond the single +// declared settlement-hook slot. It does not independently re-prove the +// borrower-exit fee hook's zero-diff — that holds by construction and is +// reviewable in the contract source. // // Requires `storageLayout` in the 0.6.11 compiler outputSelection // (hardhat.config.ts) — the shared helper throws (never silently passes) if the @@ -39,17 +41,23 @@ const assert = require("assert"); const fs = require("fs"); const path = require("path"); -const { normalizedLayout } = require("./utils/storageLayout.js"); +const { normalizedLayout, rawLayout } = require("./utils/storageLayout.js"); const BASELINE = path.join(__dirname, "baselines", "storage-layout.sovryn-perimeter-fee.json"); +const ZERO_DIFF = "zero-diff"; +const APPEND_ONLY = "append-only"; + const TARGETS = [ - "contracts/BorrowerOperations.sol:BorrowerOperations", // hooked upgradeable proxy - "contracts/ActivePool.sol:ActivePool", // native pusher — must stay untouched - "contracts/CollSurplusPool.sol:CollSurplusPool", // gains claimCollWithFee — functions only, no state + // Holds the perimeter settlement hook in one appended slot (`perimeterOps`). + { fq: "contracts/BorrowerOperations.sol:BorrowerOperations", policy: APPEND_ONLY }, + // Native pusher — must stay untouched. + { fq: "contracts/ActivePool.sol:ActivePool", policy: ZERO_DIFF }, + // Gains claimCollWithFee — functions only, no state. + { fq: "contracts/CollSurplusPool.sol:CollSurplusPool", policy: ZERO_DIFF }, ]; -describe("Perimeter — storage-layout zero-diff (Zero surplus-claim exit fee)", () => { +describe("Perimeter — storage-layout upgrade safety (surplus-claim fee hook + exit-delay reroute)", () => { let baseline; before(() => { @@ -57,7 +65,7 @@ describe("Perimeter — storage-layout zero-diff (Zero surplus-claim exit fee)", }); it("baseline snapshot is present and non-empty for every target", () => { - for (const fq of TARGETS) { + for (const { fq } of TARGETS) { assert.ok(Array.isArray(baseline[fq]), `baseline missing ${fq}`); assert.ok( baseline[fq].length > 0, @@ -66,18 +74,74 @@ describe("Perimeter — storage-layout zero-diff (Zero surplus-claim exit fee)", } }); - for (const fq of TARGETS) { - it(`${fq}: current layout == sovryn-perimeter-fee baseline (no appended state)`, async () => { - const current = await normalizedLayout(fq); - const base = baseline[fq]; - // Exact structural equality: label/slot/offset/type per entry, in order. - assert.deepStrictEqual( - current, - base, - `STORAGE LAYOUT DIFF for ${fq} vs sovryn-perimeter-fee baseline:\n` + - ` baseline entries: ${base.length}\n current entries : ${current.length}\n` + - ` current: ${JSON.stringify(current)}` - ); - }); + // The settlement companion runs under `delegatecall` in BorrowerOperations' + // context, but it does NOT share BorrowerOperations' plain-storage layout: + // BorrowerOperations also inherits LiquityBase, so any variable declared here + // would sit four words earlier than the same-named variable there. Declaring + // no storage at all is what makes that impossible to get wrong; everything + // the companion needs from the caller's state arrives as an argument, and the + // only slots it reads directly are the EIP-1967-style ones, addressed by + // constant rather than by declaration order. + it("the settlement companion declares no storage at all", async () => { + const layout = await rawLayout( + "contracts/Dependencies/BorrowerOperationsPerimeterOps.sol:BorrowerOperationsPerimeterOps" + ); + assert.deepStrictEqual( + layout, + [], + "BorrowerOperationsPerimeterOps declared storage: under delegatecall its slots do " + + "NOT line up with BorrowerOperations', so a read or write here corrupts the " + + "caller. Pass the value in as an argument instead.\n" + + ` declared: ${JSON.stringify(layout)}` + ); + }); + + for (const { fq, policy } of TARGETS) { + if (policy === ZERO_DIFF) { + it(`${fq}: current layout == sovryn-perimeter-fee baseline (no appended state)`, async () => { + const current = await normalizedLayout(fq); + const base = baseline[fq]; + // Exact structural equality: label/slot/offset/type per entry, in order. + assert.deepStrictEqual( + current, + base, + `STORAGE LAYOUT DIFF for ${fq} vs sovryn-perimeter-fee baseline:\n` + + ` baseline entries: ${base.length}\n current entries : ${current.length}\n` + + ` current: ${JSON.stringify(current)}` + ); + }); + } else { + it(`${fq}: baseline prefix unchanged, additions strictly appended`, async () => { + const current = await normalizedLayout(fq); + const base = baseline[fq]; + + assert.ok( + current.length >= base.length, + `${fq}: ${base.length - current.length} baseline entr(ies) REMOVED — ` + + `every deployed slot must survive an upgrade.\n` + + ` current: ${JSON.stringify(current)}` + ); + + // The deployed prefix must be byte-identical: no reorder, retype, + // resize or insertion anywhere inside the live layout. + assert.deepStrictEqual( + current.slice(0, base.length), + base, + `STORAGE LAYOUT DIFF inside the deployed prefix of ${fq}:\n` + + ` current: ${JSON.stringify(current.slice(0, base.length))}` + ); + + // Additions must land beyond every baseline slot, so nothing can + // pack into a slot the live contract already accounts for. + const lastBaselineSlot = base.reduce((m, e) => Math.max(m, Number(e.slot)), -1); + for (const added of current.slice(base.length)) { + assert.ok( + Number(added.slot) > lastBaselineSlot, + `${fq}: appended '${added.label}' sits at slot ${added.slot}, ` + + `inside the deployed range (last baseline slot ${lastBaselineSlot})` + ); + } + }); + } } }); diff --git a/tests-perimeter/ZeroBorrowerExit.delay.notouch.test.js b/tests-perimeter/ZeroBorrowerExit.delay.notouch.test.js new file mode 100644 index 0000000..f4cc8da --- /dev/null +++ b/tests-perimeter/ZeroBorrowerExit.delay.notouch.test.js @@ -0,0 +1,175 @@ +// Perimeter security perimeter — Zero DELAY no-touch regression. +// +// With the perimeter ACTIVE (controller enabled, d>0) and the queue WIRED, +// proves the delay reroute fires ONLY on the voluntary collateral-out chokepoint +// and is EXEMPT on the involuntary/keeper paths — liquidation, redemption, and +// stability-pool ETH-gain withdrawal route their collateral through +// TroveManager / StabilityPool, NOT through BorrowerOperations._sendCollWithExitFee, +// so the queue is never touched (lastRequestId stays 0, no RBTC escrowed). A +// keeper/liquidator/redeemer payout must never be escrowed behind a delay. + +const deploymentHelper = require("../utils/js/deploymentHelpers.js"); +const testHelpers = require("../utils/js/testHelpers.js"); +const timeMachine = require("ganache-time-traveler"); + +const BorrowerOperationsTester = artifacts.require("./BorrowerOperationsTester.sol"); +const TroveManagerTester = artifacts.require("TroveManagerTester"); +const MassetManagerTester = artifacts.require("MassetManagerTester"); +const ExitFeeControllerMock = artifacts.require("ExitFeeControllerMock"); +const MockExitDelayQueue = artifacts.require("MockExitDelayQueue"); + +const th = testHelpers.TestHelper; +const dec = th.dec; +const toBN = th.toBN; +const timeValues = testHelpers.TimeValues; +const ZERO_ADDRESS = th.ZERO_ADDRESS; + +const DELAY = 3600; +const MIN_DELAY = 100; +const GAS_PRICE = toBN(dec(1, 9)); + +contract( + "Perimeter delay — Zero no-touch (liquidation/redemption/SP-gain exempt)", + async (accounts) => { + const [owner, alice, whale, defaulter_1] = accounts; + const feeReceiver = accounts[995]; + const multisig = accounts[999]; + + let priceFeed; + let zusdToken; + let troveManager; + let activePool; + let stabilityPool; + let borrowerOperations; + let controller; + let queue; + let contracts; + + const openTrove = async (params) => th.openTrove(contracts, params); + + before(async () => { + contracts = await deploymentHelper.deployLiquityCore(); + const permit2 = contracts.permit2; + + contracts.borrowerOperations = await BorrowerOperationsTester.new(permit2.address); + contracts.massetManager = await MassetManagerTester.new(); + contracts.troveManager = await TroveManagerTester.new(permit2.address); + contracts = await deploymentHelper.deployZUSDTokenTester(contracts); + const ZEROContracts = await deploymentHelper.deployZEROTesterContractsHardhat( + multisig + ); + + await ZEROContracts.zeroToken.unprotectedMint(multisig, toBN(dec(20, 24))); + + await deploymentHelper.connectZEROContracts(ZEROContracts); + await deploymentHelper.connectCoreContracts(contracts, ZEROContracts); + await deploymentHelper.connectZEROContractsToCore(ZEROContracts, contracts); + + priceFeed = contracts.priceFeedTestnet; + zusdToken = contracts.zusdToken; + troveManager = contracts.troveManager; + activePool = contracts.activePool; + stabilityPool = contracts.stabilityPool; + borrowerOperations = contracts.borrowerOperations; + + await borrowerOperations.setMassetManagerAddress(contracts.massetManager.address); + }); + + let snapshotId; + beforeEach(async () => { + const snap = await timeMachine.takeSnapshot(); + snapshotId = snap["result"]; + controller = await ExitFeeControllerMock.new(); + queue = await MockExitDelayQueue.new(MIN_DELAY); + await queue.setAllowedSource(borrowerOperations.address, true); + // Perimeter ACTIVE + queue WIRED — so a touched queue would be visible. + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + await controller.configureDelay(true, DELAY); + }); + afterEach(async () => { + await timeMachine.revertToSnapshot(snapshotId); + }); + + const assertQueueUntouched = async () => { + assert.equal( + (await queue.lastRequestId()).toString(), + "0", + "queue recorded a request" + ); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(toBN(0)), + "queue escrowed RBTC" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(toBN(0))); + }; + + it("liquidation: collateral routes via TroveManager — queue untouched", async () => { + await priceFeed.setPrice(dec(200, 18)); + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: whale, value: toBN(dec(1000, "ether")) }, + }); + await openTrove({ ICR: toBN(dec(2, 18)), extraParams: { from: defaulter_1 } }); + + await priceFeed.setPrice(dec(100, 18)); + assert.isFalse(await th.checkRecoveryMode(contracts)); + await troveManager.liquidate(defaulter_1, { from: owner }); + + assert.equal((await troveManager.Troves(defaulter_1))[3].toString(), "3"); // closedByLiquidation + await assertQueueUntouched(); + }); + + it("redemption: collateral routes via TroveManager — queue untouched", async () => { + await priceFeed.setPrice(dec(200, 18)); + await openTrove({ + ICR: toBN(dec(20, 18)), + extraZUSDAmount: toBN(dec(50000, 18)), + extraParams: { from: whale, value: toBN(dec(1000, "ether")) }, + }); + await openTrove({ ICR: toBN(dec(2, 18)), extraParams: { from: alice } }); + + await th.fastForwardTime( + timeValues.SECONDS_IN_ONE_WEEK * 2 + timeValues.SECONDS_IN_ONE_DAY, + web3.currentProvider + ); + + const apEthBefore = await activePool.getETH(); + await th.redeemCollateral(whale, contracts, toBN(dec(1000, 18))); + + assert.isTrue( + (await activePool.getETH()).lt(apEthBefore), + "redemption moved no collateral (vacuous)" + ); + await assertQueueUntouched(); + }); + + it("stability-pool ETH-gain withdrawal: routes via StabilityPool — queue untouched", async () => { + await priceFeed.setPrice(dec(200, 18)); + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: whale, value: toBN(dec(1000, "ether")) }, + }); + await openTrove({ + ICR: toBN(dec(10, 18)), + extraZUSDAmount: toBN(dec(20000, 18)), + extraParams: { from: alice, value: toBN(dec(200, "ether")) }, + }); + await stabilityPool.provideToSP(toBN(dec(10000, 18)), ZERO_ADDRESS, { from: alice }); + + await openTrove({ ICR: toBN(dec(2, 18)), extraParams: { from: defaulter_1 } }); + await priceFeed.setPrice(dec(100, 18)); + await troveManager.liquidate(defaulter_1, { from: owner }); + await priceFeed.setPrice(dec(200, 18)); + + const gain = await stabilityPool.getDepositorETHGain(alice); + assert.isTrue(gain.gt(toBN(0)), "no ETH gain accrued — setup invalid"); + + await stabilityPool.withdrawFromSP(toBN(dec(10000, 18)), { + from: alice, + gasPrice: GAS_PRICE, + }); + await assertQueueUntouched(); + }); + } +); diff --git a/tests-perimeter/ZeroBorrowerExit.delay.selector.test.js b/tests-perimeter/ZeroBorrowerExit.delay.selector.test.js new file mode 100644 index 0000000..d44d973 --- /dev/null +++ b/tests-perimeter/ZeroBorrowerExit.delay.selector.test.js @@ -0,0 +1,182 @@ +// Perimeter security perimeter — SR1 queue custom-error SELECTOR propagation. +// +// The real ExitDelayQueue is Solidity 0.8.20 and its onlyAllowedSource guard +// reverts with the DISTINCT custom error `UnregisteredSource(address)` — the +// primary fail-closed halt signal the off-chain watcher keys on. The 0.6.11 +// BorrowerOperations delay hook calls `recordReceivedNativeExit` as a PLAIN +// external call (NOT wrapped in a try/catch or re-`require` with a PERIMETER: +// string), and BorrowerOperations re-emits the settlement hook's revert +// unchanged, so that selector must BUBBLE UP UNWRAPPED out of the reverting +// trove exit — across BOTH the pragma and the delegatecall boundary. +// +// This regression drives a real withdrawColl/closeTrove into a queue that +// reverts with the exact `UnregisteredSource(msg.sender)` payload and asserts +// the returndata's leading 4 bytes equal the queue's selector (and are NOT a +// PERIMETER:-prefixed host string). The COMPANION host-side pre-check strings +// (PERIMETER:queue-unset / PERIMETER:delay-quote-failed) are asserted in +// ZeroBorrowerExit.delay.test.js — those are the reverts that CANNOT bubble a +// queue selector because they fire before/around the queue call. +// +// The revert payload is read ON-CHAIN through `PerimeterRawCatcher`, which +// low-level-calls BorrowerOperations and RETURNS the raw returndata. That is +// the EVM's own answer, and it holds whether or not the node can decode a +// custom error or build a stack trace through the settlement delegatecall — +// which parsing the node's error object cannot. + +const deploymentHelper = require("../utils/js/deploymentHelpers.js"); +const testHelpers = require("../utils/js/testHelpers.js"); +const timeMachine = require("ganache-time-traveler"); + +const BorrowerOperationsTester = artifacts.require("./BorrowerOperationsTester.sol"); +const TroveManagerTester = artifacts.require("TroveManagerTester"); +const MassetManagerTester = artifacts.require("MassetManagerTester"); +const ExitFeeControllerMock = artifacts.require("ExitFeeControllerMock"); +const SelectorRevertingExitDelayQueue = artifacts.require("SelectorRevertingExitDelayQueue"); +const PerimeterRawCatcher = artifacts.require("PerimeterRawCatcher"); + +const th = testHelpers.TestHelper; +const dec = th.dec; +const toBN = th.toBN; + +const DELAY = 3600; + +// bytes4(keccak256("UnregisteredSource(address)")) — the queue's distinct halt selector. +const UNREGISTERED_SOURCE_SELECTOR = web3.utils + .keccak256("UnregisteredSource(address)") + .slice(0, 10); + +contract("Perimeter delay — SR1 queue selector propagation", async (accounts) => { + const [owner] = accounts; + const multisig = accounts[999]; + + let borrowerOperations; + let controller; + let queue; + let catcher; + let contracts; + + const openTrove = async (params) => th.openTrove(contracts, params); + + // withdrawColl/closeTrove act on msg.sender's trove, so the catcher opens its + // own and drives the exit itself — the returndata it receives IS the payload + // the reverting exit hands its caller. + const catcherCall = (data) => + catcher.probe.call(borrowerOperations.address, data, { from: owner }); + + before(async () => { + contracts = await deploymentHelper.deployLiquityCore(); + const permit2 = contracts.permit2; + + contracts.borrowerOperations = await BorrowerOperationsTester.new(permit2.address); + contracts.massetManager = await MassetManagerTester.new(); + contracts.troveManager = await TroveManagerTester.new(permit2.address); + contracts = await deploymentHelper.deployZUSDTokenTester(contracts); + const ZEROContracts = await deploymentHelper.deployZEROTesterContractsHardhat(multisig); + + await ZEROContracts.zeroToken.unprotectedMint(multisig, toBN(dec(20, 24))); + await deploymentHelper.connectZEROContracts(ZEROContracts); + await deploymentHelper.connectCoreContracts(contracts, ZEROContracts); + await deploymentHelper.connectZEROContractsToCore(ZEROContracts, contracts); + + borrowerOperations = contracts.borrowerOperations; + await borrowerOperations.setMassetManagerAddress(contracts.massetManager.address); + catcher = await PerimeterRawCatcher.new(); + }); + + let snapshotId; + beforeEach(async () => { + const snap = await timeMachine.takeSnapshot(); + snapshotId = snap["result"]; + controller = await ExitFeeControllerMock.new(); + queue = await SelectorRevertingExitDelayQueue.new(); + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + await controller.configureDelay(true, DELAY); // d>0 ⇒ the reroute engages the queue + }); + afterEach(async () => { + await timeMachine.revertToSnapshot(snapshotId); + }); + + // A trove owned by the catcher: 100 RBTC of collateral against a small draw, + // so it stays far above MCR and can also be closed within a test. + const openCatcherTrove = async () => { + const data = borrowerOperations.contract.methods + .openTrove( + toBN(dec(5, 16)).toString(), // maxFeePercentage 5% + toBN(dec(2000, 18)).toString(), + catcher.address, + catcher.address + ) + .encodeABI(); + await catcher.probe(borrowerOperations.address, data, { + from: owner, + value: toBN(dec(100, "ether")), + }); + assert.equal( + (await contracts.troveManager.getTroveStatus(catcher.address)).toString(), + "1", + "catcher trove was not opened" + ); + }; + + it("sanity: the mock reverts with the exact UnregisteredSource(address) selector", async () => { + const sel = await queue.UNREGISTERED_SOURCE_SELECTOR(); + assert.equal( + sel.toLowerCase(), + UNREGISTERED_SOURCE_SELECTOR, + "mock selector != keccak selector" + ); + }); + + it("withdrawColl (d>0): queue UnregisteredSource selector BUBBLES UP unwrapped (not a PERIMETER: string)", async () => { + await openCatcherTrove(); + + const data = borrowerOperations.contract.methods + .withdrawColl(toBN(dec(1, "ether")).toString(), catcher.address, catcher.address) + .encodeABI(); + const { ok, ret: revertData } = await catcherCall(data); + + assert.isFalse(ok, "expected the exit to revert"); + // Distinct 4-byte selector preserved cross-pragma (0.8.20 queue → 0.6.11 + // host) and across the settlement delegatecall. + assert.equal( + revertData.toLowerCase().slice(0, 10), + UNREGISTERED_SOURCE_SELECTOR, + `expected queue selector to bubble; got ${revertData}` + ); + // The bubbled payload ABI-encodes the offending caller (the BO proxy), proving + // the FULL custom-error data survived — not a truncated / re-wrapped revert. + const encodedCaller = borrowerOperations.address.slice(2).toLowerCase().padStart(64, "0"); + assert.include( + revertData.toLowerCase(), + encodedCaller, + "custom-error arg (caller) not preserved" + ); + }); + + it("closeTrove (d>0): queue selector bubbles out of a failing trove CLOSE (fail-closed)", async () => { + // A second trove so the catcher can close its own (system keeps >1 trove). + await openTrove({ + extraZUSDAmount: toBN(dec(20000, 18)), + ICR: toBN(dec(3, 18)), + extraParams: { from: owner }, + }); + await openCatcherTrove(); + // closeTrove burns ZUSD from the caller — fund the catcher to cover its debt. + await contracts.zusdToken.transfer( + catcher.address, + await contracts.zusdToken.balanceOf(owner), + { from: owner } + ); + + const data = borrowerOperations.contract.methods.closeTrove().encodeABI(); + const { ok, ret: revertData } = await catcherCall(data); + + assert.isFalse(ok, "expected the close to revert"); + assert.equal( + revertData.toLowerCase().slice(0, 10), + UNREGISTERED_SOURCE_SELECTOR, + `expected queue selector to bubble out of closeTrove; got ${revertData}` + ); + }); +}); diff --git a/tests-perimeter/ZeroBorrowerExit.delay.test.js b/tests-perimeter/ZeroBorrowerExit.delay.test.js new file mode 100644 index 0000000..4be0f74 --- /dev/null +++ b/tests-perimeter/ZeroBorrowerExit.delay.test.js @@ -0,0 +1,496 @@ +// Perimeter security perimeter — Zero borrower exit DELAY hook +// (surface PERIMETER_SURFACE_ZERO_WITHDRAW_COLL). +// +// Proves the delay reroute at the single voluntary collateral-out chokepoint +// `_sendCollWithExitFee` (reached by withdrawColl, collateral-decreasing +// adjustTrove, and closeTrove): +// - d>0 ⇒ the borrower USER leg (net on fee-ok, GROSS on fee-fail) is +// PUSHED to the queue via ActivePool.sendETH and recorded via +// recordReceivedNativeExit in the SAME tx; the borrower is NOT paid directly; +// - d==0 (perimeter disabled / unwired controller) ⇒ direct pay, byte-for-byte +// baseline, and the queue is NEVER touched; +// - fee + delay compose: fee leg to feeReceiver, delayed leg to the queue; +// - FAIL-CLOSED: a controller-quote revert, an unwired queue at d>0, or a +// record revert reverts the WHOLE exit atomically (trove state rolls back); +// - executeExit pays the immutable receiver after unlock; a blocked actor +// cannot execute (block-trap); +// - conservation: escrowed(net) + fee == gross, ActivePool drained by gross. + +const deploymentHelper = require("../utils/js/deploymentHelpers.js"); +const testHelpers = require("../utils/js/testHelpers.js"); +const timeMachine = require("ganache-time-traveler"); + +const BorrowerOperationsTester = artifacts.require("./BorrowerOperationsTester.sol"); +const TroveManagerTester = artifacts.require("TroveManagerTester"); +const MassetManagerTester = artifacts.require("MassetManagerTester"); +const ExitFeeControllerMock = artifacts.require("ExitFeeControllerMock"); +const MockExitDelayQueue = artifacts.require("MockExitDelayQueue"); +const NonPayable = artifacts.require("NonPayable"); + +const th = testHelpers.TestHelper; +const dec = th.dec; +const toBN = th.toBN; +const ZERO_ADDRESS = th.ZERO_ADDRESS; + +const GAS_PRICE = toBN(dec(1, 9)); +const DELAY = 3600; // 1h +const MIN_DELAY = 100; +const SURFACE = web3.utils.keccak256("PERIMETER_SURFACE_ZERO_WITHDRAW_COLL"); + +contract("Perimeter delay — Zero borrower exit reroute", async (accounts) => { + const [owner, alice, dennis] = accounts; + const feeReceiver = accounts[995]; + const multisig = accounts[999]; + + let zusdToken; + let troveManager; + let activePool; + let sortedTroves; + let borrowerOperations; + let controller; + let queue; + let contracts; + + const openTrove = async (params) => th.openTrove(contracts, params); + const getTroveEntireColl = async (trove) => th.getTroveEntireColl(contracts, trove); + const getEvent = (tx, name) => tx.logs.find((l) => l.event === name); + const bal = async (a) => toBN(await web3.eth.getBalance(a)); + + before(async () => { + contracts = await deploymentHelper.deployLiquityCore(); + const permit2 = contracts.permit2; + + contracts.borrowerOperations = await BorrowerOperationsTester.new(permit2.address); + contracts.massetManager = await MassetManagerTester.new(); + contracts.troveManager = await TroveManagerTester.new(permit2.address); + contracts = await deploymentHelper.deployZUSDTokenTester(contracts); + const ZEROContracts = await deploymentHelper.deployZEROTesterContractsHardhat(multisig); + + await ZEROContracts.zeroToken.unprotectedMint(multisig, toBN(dec(20, 24))); + + await deploymentHelper.connectZEROContracts(ZEROContracts); + await deploymentHelper.connectCoreContracts(contracts, ZEROContracts); + await deploymentHelper.connectZEROContractsToCore(ZEROContracts, contracts); + + zusdToken = contracts.zusdToken; + troveManager = contracts.troveManager; + activePool = contracts.activePool; + sortedTroves = contracts.sortedTroves; + borrowerOperations = contracts.borrowerOperations; + + await borrowerOperations.setMassetManagerAddress(contracts.massetManager.address); + }); + + let snapshotId; + beforeEach(async () => { + const snap = await timeMachine.takeSnapshot(); + snapshotId = snap["result"]; + controller = await ExitFeeControllerMock.new(); + queue = await MockExitDelayQueue.new(MIN_DELAY); + await queue.setAllowedSource(borrowerOperations.address, true); + }); + afterEach(async () => { + await timeMachine.revertToSnapshot(snapshotId); + }); + + // Wire the controller (+ optional queue pointer) and enable the perimeter with `d`. + const wire = async ({ + delaySecs = DELAY, + wireQueue = true, + feeActive = false, + rateBps = 0, + } = {}) => { + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + if (wireQueue) await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + await controller.configureDelay(true, delaySecs); + if (feeActive) await controller.configure(true, rateBps, feeReceiver, 0); + }; + + const setupCloseable = async () => { + await openTrove({ + extraZUSDAmount: toBN(dec(10000, 18)), + ICR: toBN(dec(2, 18)), + extraParams: { from: dennis }, + }); + await openTrove({ + extraZUSDAmount: toBN(dec(10000, 18)), + ICR: toBN(dec(2, 18)), + extraParams: { from: alice }, + }); + await zusdToken.transfer(alice, await zusdToken.balanceOf(dennis), { from: dennis }); + }; + + // ── Pointer wiring ────────────────────────────────────────────────────── + + it("setExitDelayQueue: only owner, rejects zero + non-contract, rotatable, emits event", async () => { + await th.assertRevert( + borrowerOperations.setExitDelayQueue(queue.address, { from: alice }) + ); + await th.assertRevert(borrowerOperations.setExitDelayQueue(ZERO_ADDRESS, { from: owner })); + await th.assertRevert(borrowerOperations.setExitDelayQueue(alice, { from: owner })); // EOA / no code + + const tx = await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + assert.equal(await borrowerOperations.exitDelayQueue(), queue.address); + const ev = getEvent(tx, "ExitDelayQueueSet"); + assert.isDefined(ev); + assert.equal(ev.args.current, queue.address); + + const queue2 = await MockExitDelayQueue.new(MIN_DELAY); + await borrowerOperations.setExitDelayQueue(queue2.address, { from: owner }); + assert.equal(await borrowerOperations.exitDelayQueue(), queue2.address); + }); + + // ── withdrawColl reroute (d>0, no fee) ────────────────────────────────── + + it("withdrawColl (d>0, fee inactive): GROSS escrowed to queue, borrower NOT paid, ActivePool -= gross", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire(); + + const gross = toBN(dec(1, "ether")); + const apBefore = await activePool.getETH(); + const aliceBefore = await bal(alice); + const collBefore = await getTroveEntireColl(alice); + + const tx = await borrowerOperations.withdrawColl(gross, alice, alice, { + from: alice, + gasPrice: GAS_PRICE, + }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + // ActivePool drained by exactly gross; the queue now custodies it. + assert.isTrue((await activePool.getETH()).eq(apBefore.sub(gross)), "ActivePool != -gross"); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(gross), + "queue balance != gross" + ); + assert.isTrue( + (await queue.totalEscrowed(ZERO_ADDRESS)).eq(gross), + "totalEscrowed != gross" + ); + // borrower received NOTHING directly (only lost gas) — the leg is escrowed. + assert.isTrue( + (await bal(alice)).eq(aliceBefore.sub(gasCost)), + "borrower paid directly on a delayed exit" + ); + assert.isTrue( + (await getTroveEntireColl(alice)).eq(collBefore.sub(gross)), + "trove coll not reduced" + ); + + // one request, immutable metadata: originator=owner=receiver=alice, token=native. + assert.equal((await queue.lastRequestId()).toString(), "1"); + const r = await queue.getRequest(1); + assert.equal(r.originator, alice); + assert.equal(r.owner, alice); + assert.equal(r.receiver, alice); + assert.equal(r.token, ZERO_ADDRESS); + assert.equal(r.surfaceId, SURFACE); + assert.isTrue(toBN(r.amount).eq(gross)); + assert.equal(toBN(r.unlockAt).sub(toBN(r.createdAt)).toString(), String(DELAY)); + }); + + // ── fee + delay compose (d>0, fee active) ─────────────────────────────── + + it("withdrawColl (d>0, fee 50bps): fee→feeReceiver, NET→queue, ExitFeeApplied; sums to gross", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire({ feeActive: true, rateBps: 50 }); + + const gross = toBN(dec(1, "ether")); + const fee = gross.mul(toBN(50)).div(toBN(10000)); + const net = gross.sub(fee); + + const apBefore = await activePool.getETH(); + const frBefore = await bal(feeReceiver); + + const tx = await borrowerOperations.withdrawColl(gross, alice, alice, { from: alice }); + + assert.isTrue((await activePool.getETH()).eq(apBefore.sub(gross)), "ActivePool != -gross"); + assert.isTrue((await bal(feeReceiver)).eq(frBefore.add(fee)), "feeReceiver != +fee"); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(net), + "queue != +net (delayed leg)" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(net)); + // conservation: fee + escrowed net == gross + assert.isTrue(fee.add(net).eq(gross)); + + const applied = getEvent(tx, "ExitFeeApplied"); + assert.isDefined(applied, "ExitFeeApplied not emitted"); + assert.isTrue(toBN(applied.args.netAmount).eq(net)); + const r = await queue.getRequest(1); + assert.isTrue(toBN(r.amount).eq(net), "escrowed amount != net"); + }); + + // ── fee-vault failure still escrows GROSS behind the delay ────────────── + + it("withdrawColl (d>0, fee-vault reverts): GROSS escrowed behind the delay (cannot bypass), ExitFeeSkipped(VAULT_REVERT)", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + const badReceiver = await NonPayable.new(); + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + await controller.configureDelay(true, DELAY); + await controller.configure(true, 50, badReceiver.address, 0); // fee active but receiver bounces + + const gross = toBN(dec(1, "ether")); + const apBefore = await activePool.getETH(); + + const tx = await borrowerOperations.withdrawColl(gross, alice, alice, { from: alice }); + + // fee leg bounced ⇒ full GROSS routed to the queue (NOT paid direct, NOT skimmed). + assert.isTrue((await activePool.getETH()).eq(apBefore.sub(gross)), "ActivePool != -gross"); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(gross), + "gross not escrowed on fee-fail" + ); + assert.isTrue( + toBN(await web3.eth.getBalance(badReceiver.address)).eq(toBN(0)), + "bad receiver got ETH" + ); + assert.equal(toBN(getEvent(tx, "ExitFeeSkipped").args.reason).toNumber(), 5); // VAULT_REVERT + const r = await queue.getRequest(1); + assert.isTrue(toBN(r.amount).eq(gross)); + }); + + // ── closeTrove + adjustTrove reroute ──────────────────────────────────── + + it("closeTrove (d>0): entire collateral escrowed, trove removed, ActivePool -= coll", async () => { + await setupCloseable(); + await wire(); + const gross = await getTroveEntireColl(alice); + const apBefore = await activePool.getETH(); + + await borrowerOperations.closeTrove({ from: alice }); + + assert.isTrue((await activePool.getETH()).eq(apBefore.sub(gross)), "ActivePool != -coll"); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(gross), + "coll not escrowed" + ); + assert.isFalse(await sortedTroves.contains(alice), "trove not removed"); + const r = await queue.getRequest(1); + assert.isTrue(toBN(r.amount).eq(gross)); + assert.equal(r.receiver, alice); + }); + + it("adjustTrove (coll-decreasing, d>0): withdrawal escrowed; debt-only adjust never touches the queue", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire(); + + // coll-decreasing adjust (withdraw 2 ETH, no debt change) + const w = toBN(dec(2, "ether")); + await borrowerOperations.adjustTrove(0, w, 0, false, alice, alice, { from: alice }); + assert.equal((await queue.lastRequestId()).toString(), "1"); + assert.isTrue(toBN(await web3.eth.getBalance(queue.address)).eq(w)); + + // debt-increase-only adjust (no collateral out) ⇒ gross==0 ⇒ hook early-returns, queue untouched + await borrowerOperations.adjustTrove( + toBN(dec(1, 18)), + 0, + toBN(dec(100, 18)), + true, + alice, + alice, + { from: alice } + ); + assert.equal( + (await queue.lastRequestId()).toString(), + "1", + "debt-only adjust touched the queue" + ); + }); + + // ── d==0 direct pay, queue never touched ──────────────────────────────── + + it("perimeter disabled (d==0): direct pay to borrower, queue NEVER touched even when wired", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + // controller + queue wired, but perimeter OFF ⇒ quoteExitDelayFor returns d=0. + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + await controller.configureDelay(false, DELAY); + + const gross = toBN(dec(1, "ether")); + const aliceBefore = await bal(alice); + const tx = await borrowerOperations.withdrawColl(gross, alice, alice, { + from: alice, + gasPrice: GAS_PRICE, + }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + // borrower paid directly; queue untouched. + assert.isTrue( + (await bal(alice)).eq(aliceBefore.add(gross).sub(gasCost)), + "borrower not paid direct at d==0" + ); + assert.equal((await queue.lastRequestId()).toString(), "0", "queue touched at d==0"); + assert.isTrue(toBN(await web3.eth.getBalance(queue.address)).eq(toBN(0))); + }); + + it("controller unwired (no pointer): fail-open direct pay at d==0 (perimeter unreachable)", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + // No controller set at all ⇒ _safeQuoteExitDelay short-circuits to (0, raw, raw). + const gross = toBN(dec(1, "ether")); + const aliceBefore = await bal(alice); + const tx = await borrowerOperations.withdrawColl(gross, alice, alice, { + from: alice, + gasPrice: GAS_PRICE, + }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + assert.isTrue((await bal(alice)).eq(aliceBefore.add(gross).sub(gasCost))); + assert.equal((await queue.lastRequestId()).toString(), "0"); + }); + + // ── FAIL-CLOSED legs ──────────────────────────────────────────────────── + + it("FAIL-CLOSED: controller quote reverts ⇒ whole withdrawColl reverts, trove unchanged", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire(); + await controller.setDelayRevert(true); + + const collBefore = await getTroveEntireColl(alice); + await th.assertRevert( + borrowerOperations.withdrawColl(toBN(dec(1, "ether")), alice, alice, { from: alice }), + "PERIMETER:delay-quote-failed" + ); + assert.isTrue( + (await getTroveEntireColl(alice)).eq(collBefore), + "trove mutated on a fail-closed revert" + ); + }); + + it("FAIL-CLOSED: d>0 but queue unwired ⇒ whole withdrawColl reverts (delay never silently bypassed)", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + // controller enabled with d>0, but the queue pointer is NEVER set. + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await controller.configureDelay(true, DELAY); + + const collBefore = await getTroveEntireColl(alice); + await th.assertRevert( + borrowerOperations.withdrawColl(toBN(dec(1, "ether")), alice, alice, { from: alice }), + "PERIMETER:queue-unset" + ); + assert.isTrue((await getTroveEntireColl(alice)).eq(collBefore)); + }); + + it("FAIL-CLOSED: a bricked queue (record reverts) reverts the whole close atomically", async () => { + await setupCloseable(); + await wire(); + // De-register BO as an allowed source ⇒ recordReceivedNativeExit reverts. + await queue.setAllowedSource(borrowerOperations.address, false); + + const collBefore = await getTroveEntireColl(alice); + const apBefore = await activePool.getETH(); + await th.assertRevert(borrowerOperations.closeTrove({ from: alice })); + // trove + pool fully rolled back — no partial close, no orphaned push. + assert.isTrue( + (await getTroveEntireColl(alice)).eq(collBefore), + "trove partially closed on fail-closed" + ); + assert.isTrue( + (await activePool.getETH()).eq(apBefore), + "ActivePool drained on fail-closed" + ); + assert.isTrue(await sortedTroves.contains(alice), "trove removed on fail-closed"); + }); + + // ── executeExit after unlock + block-trap ─────────────────────────────── + + it("executeExit: reverts before unlock, pays the receiver after unlock", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire(); + const gross = toBN(dec(1, "ether")); + await borrowerOperations.withdrawColl(gross, alice, alice, { from: alice }); + + await th.assertRevert(queue.executeExit(1, { from: alice }), "not unlocked"); + + await th.fastForwardTime(DELAY + 1, web3.currentProvider); + const aliceBefore = await bal(alice); + const tx = await queue.executeExit(1, { from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + assert.isTrue( + (await bal(alice)).eq(aliceBefore.add(gross).sub(gasCost)), + "receiver not paid on execute" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(toBN(0))); + }); + + it("block-trap: a frozen actor cannot execute the escrowed exit", async () => { + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: alice, value: toBN(dec(100, "ether")) }, + }); + await wire(); + await borrowerOperations.withdrawColl(toBN(dec(1, "ether")), alice, alice, { + from: alice, + }); + await th.fastForwardTime(DELAY + 1, web3.currentProvider); + + await queue.freeze(alice); + await th.assertRevert(queue.executeExit(1, { from: alice }), "actor blocked"); + await queue.unfreeze(alice); + await queue.executeExit(1, { from: alice }); // succeeds once unblocked + }); + + // ── property/fuzz: escrow == net and conservation over random amounts ──── + + it("property (fuzz): over random withdrawals, escrowed == net and fee+net == gross", async () => { + await openTrove({ + ICR: toBN(dec(50, 18)), + extraParams: { from: alice, value: toBN(dec(500, "ether")) }, + }); + await wire({ feeActive: true, rateBps: 137 }); + + for (let i = 0; i < 12; i++) { + const inner = (await timeMachine.takeSnapshot())["result"]; + // random gross in [1, 10] ether, at 1e12-wei granularity + const units = toBN(1 + Math.floor(Math.random() * 9)); // 1..9 ether + const extra = toBN(String(Math.floor(Math.random() * 1e6))).mul(toBN(dec(1, 12))); + const gross = units.mul(toBN(dec(1, 18))).add(extra); + const fee = gross.mul(toBN(137)).div(toBN(10000)); + const net = gross.sub(fee); + + const apBefore = await activePool.getETH(); + await borrowerOperations.withdrawColl(gross, alice, alice, { from: alice }); + + const escrowed = await queue.totalEscrowed(ZERO_ADDRESS); + assert.isTrue(escrowed.eq(net), `escrowed(${escrowed}) != net(${net})`); + assert.isTrue(fee.add(net).eq(gross), "fee+net != gross"); + assert.isTrue( + (await activePool.getETH()).eq(apBefore.sub(gross)), + "ActivePool != -gross" + ); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(net), + "queue balance != net" + ); + + await timeMachine.revertToSnapshot(inner); + } + }); +}); diff --git a/tests-perimeter/ZeroClaimSurplus.delay.test.js b/tests-perimeter/ZeroClaimSurplus.delay.test.js new file mode 100644 index 0000000..af0eee7 --- /dev/null +++ b/tests-perimeter/ZeroClaimSurplus.delay.test.js @@ -0,0 +1,326 @@ +// Perimeter security perimeter — surplus-claim DELAY hook +// (surface PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS). +// +// The surplus claim composes the fee leg and the delay leg the same way the +// voluntary collateral exit does, with one structural difference: the pool, not +// ActivePool, holds the funds, so the net leg is sent by +// `CollSurplusPool.claimCollWithFeeTo` and recorded by BorrowerOperations in the +// same transaction. +// +// - d>0 ⇒ the claimant's leg (net on fee-ok, GROSS on the uncharged path) is +// PUSHED to the queue by the pool and recorded via recordReceivedNativeExit +// in the SAME tx; the claimant is NOT paid directly; +// - d==0 (perimeter disabled / unwired controller) ⇒ the untouched claim, and +// the queue is NEVER touched; +// - the FEE leg stays fail-OPEN and the DELAY leg fail-CLOSED: an unwired +// queue or a reverting record reverts the whole claim and the claimant keeps +// their surplus balance to claim again; +// - conservation: escrowed(net) + fee == gross, the pool drained by gross; +// - executeExit pays the claimant after unlock. +// +// This supersedes the earlier exemption pinning: the surplus surface was +// initially delay-exempt by design, and that decision was reversed. + +const deploymentHelper = require("../utils/js/deploymentHelpers.js"); +const testHelpers = require("../utils/js/testHelpers.js"); +const timeMachine = require("ganache-time-traveler"); + +const BorrowerOperationsTester = artifacts.require("./BorrowerOperationsTester.sol"); +const TroveManagerTester = artifacts.require("TroveManagerTester"); +const MassetManagerTester = artifacts.require("MassetManagerTester"); +const ExitFeeControllerMock = artifacts.require("ExitFeeControllerMock"); +const MockExitDelayQueue = artifacts.require("MockExitDelayQueue"); + +const th = testHelpers.TestHelper; +const dec = th.dec; +const toBN = th.toBN; +const timeValues = testHelpers.TimeValues; +const ZERO_ADDRESS = th.ZERO_ADDRESS; + +const NONE = 0; +const DELAY = 3600; // 1h +const MIN_DELAY = 100; +const GAS_PRICE = toBN(dec(1, 9)); +const SURFACE = web3.utils.keccak256("PERIMETER_SURFACE_ZERO_CLAIM_SURPLUS"); + +contract("Perimeter delay — Zero surplus claim reroute", async (accounts) => { + const [owner, alice, whale, dennis] = accounts; + const feeReceiver = accounts[995]; + const multisig = accounts[999]; + + let priceFeed; + let collSurplusPool; + let borrowerOperations; + let controller; + let queue; + let contracts; + + const openTrove = async (params) => th.openTrove(contracts, params); + const getEvent = (tx, name) => tx.logs.find((l) => l.event === name); + + before(async () => { + contracts = await deploymentHelper.deployLiquityCore(); + const permit2 = contracts.permit2; + + contracts.borrowerOperations = await BorrowerOperationsTester.new(permit2.address); + contracts.massetManager = await MassetManagerTester.new(); + contracts.troveManager = await TroveManagerTester.new(permit2.address); + contracts = await deploymentHelper.deployZUSDTokenTester(contracts); + const ZEROContracts = await deploymentHelper.deployZEROTesterContractsHardhat(multisig); + + await ZEROContracts.zeroToken.unprotectedMint(multisig, toBN(dec(20, 24))); + + await deploymentHelper.connectZEROContracts(ZEROContracts); + await deploymentHelper.connectCoreContracts(contracts, ZEROContracts); + await deploymentHelper.connectZEROContractsToCore(ZEROContracts, contracts); + + priceFeed = contracts.priceFeedTestnet; + collSurplusPool = contracts.collSurplusPool; + borrowerOperations = contracts.borrowerOperations; + + await borrowerOperations.setMassetManagerAddress(contracts.massetManager.address); + }); + + let snapshotId; + beforeEach(async () => { + const snap = await timeMachine.takeSnapshot(); + snapshotId = snap["result"]; + controller = await ExitFeeControllerMock.new(); + queue = await MockExitDelayQueue.new(MIN_DELAY); + await queue.setAllowedSource(borrowerOperations.address, true); + await borrowerOperations.setExitFeeController(controller.address, { from: owner }); + await controller.configureDelay(true, DELAY); + }); + afterEach(async () => { + await timeMachine.revertToSnapshot(snapshotId); + }); + + // Fully redeem a ~200%-ICR trove at ETH:USD = 100; the surplus + // (coll - netDebt/price) stays claimable by its owner. + const setupSurplus = async (claimant) => { + const price = toBN(dec(100, 18)); + await priceFeed.setPrice(price); + const { netDebt } = await openTrove({ + ICR: toBN(dec(200, 16)), + extraParams: { from: claimant }, + }); + await openTrove({ + extraZUSDAmount: netDebt, + extraParams: { from: whale, value: dec(3000, "ether") }, + }); + await th.fastForwardTime(timeValues.SECONDS_IN_ONE_WEEK * 2, web3.currentProvider); + await th.redeemCollateralAndGetTxObject(whale, contracts, netDebt); + const gross = await collSurplusPool.getCollateral(claimant); + assert.isTrue(gross.gt(toBN(0)), "setup failed: no surplus created"); + return gross; + }; + + // The queue pointer rejects address(0) by design, so "unwired" can only be + // expressed by never setting it — hence wiring is per-test, not shared setup. + const wireQueue = () => borrowerOperations.setExitDelayQueue(queue.address, { from: owner }); + + const assertQueueUntouched = async () => { + assert.equal((await queue.lastRequestId()).toString(), "0", "queue recorded a request"); + assert.isTrue( + toBN(await web3.eth.getBalance(queue.address)).eq(toBN(0)), + "queue escrowed RBTC" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(toBN(0))); + }; + + it("CONTROL (non-vacuous): the SAME arming reroutes a voluntary withdrawColl", async () => { + await wireQueue(); + await priceFeed.setPrice(dec(200, 18)); + await openTrove({ + ICR: toBN(dec(10, 18)), + extraParams: { from: dennis, value: toBN(dec(100, "ether")) }, + }); + const amount = toBN(dec(1, "ether")); + await borrowerOperations.withdrawColl(amount, dennis, dennis, { from: dennis }); + + assert.equal((await queue.lastRequestId()).toString(), "1"); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(amount)); + }); + + it("fee-OFF claim (d>0): FULL gross escrowed, claimant NOT paid, pool drained", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + + const aliceBefore = toBN(await web3.eth.getBalance(alice)); + const tx = await borrowerOperations.claimCollateral({ from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + assert.isTrue( + toBN(await web3.eth.getBalance(alice)).eq(aliceBefore.sub(gasCost)), + "claimant was paid directly despite the hold" + ); + assert.isTrue( + (await collSurplusPool.getCollateral(alice)).eq(toBN(0)), + "claimable not zeroed" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(gross), "escrowed != gross"); + assert.isDefined( + getEvent(tx, "ExitFeeSkipped"), + "uncharged path must emit ExitFeeSkipped" + ); + + const request = await queue.getRequest(1); + assert.equal(request.receiver, alice, "receiver must be the claimant"); + assert.equal(request.originator, alice); + assert.equal(request.owner, alice); + assert.equal(request.surfaceId, SURFACE, "wrong surface recorded"); + assert.equal(request.token, ZERO_ADDRESS, "surplus is native RBTC"); + }); + + it("fee-ON claim (50 bps, d>0): fee to the receiver, NET escrowed, sums to gross", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await controller.configure(true, 50, feeReceiver, NONE); + + const fee = gross.mul(toBN(50)).div(toBN(10000)); + const net = gross.sub(fee); + + const frBefore = toBN(await web3.eth.getBalance(feeReceiver)); + const aliceBefore = toBN(await web3.eth.getBalance(alice)); + const tx = await borrowerOperations.claimCollateral({ from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + assert.isTrue( + toBN(await web3.eth.getBalance(feeReceiver)).eq(frBefore.add(fee)), + "feeReceiver != +fee" + ); + assert.isTrue( + toBN(await web3.eth.getBalance(alice)).eq(aliceBefore.sub(gasCost)), + "claimant was paid directly despite the hold" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(net), "escrowed != net"); + assert.isTrue( + (await queue.totalEscrowed(ZERO_ADDRESS)).add(fee).eq(gross), + "escrowed + fee != gross" + ); + assert.isDefined(getEvent(tx, "ExitFeeApplied"), "charging path must emit ExitFeeApplied"); + }); + + it("perimeter disabled (d==0): the untouched claim, queue NEVER touched", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await controller.configureDelay(false, DELAY); + + const aliceBefore = toBN(await web3.eth.getBalance(alice)); + const tx = await borrowerOperations.claimCollateral({ from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + assert.isTrue( + toBN(await web3.eth.getBalance(alice)).eq(aliceBefore.add(gross).sub(gasCost)), + "claimant != +FULL gross instantly" + ); + await assertQueueUntouched(); + }); + + it("perimeter disabled (d==0), fee ON: fee and net both paid instantly", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await controller.configureDelay(false, DELAY); + await controller.configure(true, 50, feeReceiver, NONE); + + const fee = gross.mul(toBN(50)).div(toBN(10000)); + const net = gross.sub(fee); + + const frBefore = toBN(await web3.eth.getBalance(feeReceiver)); + const aliceBefore = toBN(await web3.eth.getBalance(alice)); + const tx = await borrowerOperations.claimCollateral({ from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + assert.isTrue(toBN(await web3.eth.getBalance(feeReceiver)).eq(frBefore.add(fee))); + assert.isTrue( + toBN(await web3.eth.getBalance(alice)).eq(aliceBefore.add(net).sub(gasCost)), + "claimant != +net instantly" + ); + await assertQueueUntouched(); + }); + + it("FAIL-CLOSED: d>0 but the queue is unwired ⇒ the whole claim reverts", async () => { + // wireQueue() deliberately NOT called: the controller quotes a hold and + // there is nowhere to escrow it. + const gross = await setupSurplus(alice); + + await th.assertRevert( + borrowerOperations.claimCollateral({ from: alice }), + "PERIMETER:queue-unset" + ); + assert.isTrue( + (await collSurplusPool.getCollateral(alice)).eq(gross), + "surplus must survive a refused claim" + ); + }); + + it("FAIL-CLOSED: a reverting delay quote reverts the whole claim", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await controller.setDelayRevert(true); + + await th.assertRevert( + borrowerOperations.claimCollateral({ from: alice }), + "PERIMETER:delay-quote-failed" + ); + assert.isTrue((await collSurplusPool.getCollateral(alice)).eq(gross)); + }); + + it("FAIL-CLOSED: a bricked queue (record reverts) reverts the whole claim", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await queue.setAllowedSource(borrowerOperations.address, false); + + await th.assertRevert(borrowerOperations.claimCollateral({ from: alice })); + assert.isTrue( + (await collSurplusPool.getCollateral(alice)).eq(gross), + "surplus must survive a refused claim" + ); + await assertQueueUntouched(); + }); + + it("100% fee policy (d>0): nothing to escrow, the claim still settles", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await controller.configure(true, 10000, feeReceiver, NONE); + + const frBefore = toBN(await web3.eth.getBalance(feeReceiver)); + const tx = await borrowerOperations.claimCollateral({ from: alice }); + + assert.isTrue( + toBN(await web3.eth.getBalance(feeReceiver)).eq(frBefore.add(gross)), + "feeReceiver != +gross" + ); + assert.isDefined(getEvent(tx, "ExitFeeApplied")); + await assertQueueUntouched(); + }); + + it("executeExit: reverts before unlock, pays the claimant after", async () => { + await wireQueue(); + const gross = await setupSurplus(alice); + await borrowerOperations.claimCollateral({ from: alice, gasPrice: GAS_PRICE }); + + await th.assertRevert(queue.executeExit(1, { from: alice }), "MockQueue: not unlocked"); + + await th.fastForwardTime(DELAY + 1, web3.currentProvider); + const aliceBefore = toBN(await web3.eth.getBalance(alice)); + const tx = await queue.executeExit(1, { from: alice, gasPrice: GAS_PRICE }); + const gasCost = GAS_PRICE.mul(toBN(tx.receipt.gasUsed)); + + assert.isTrue( + toBN(await web3.eth.getBalance(alice)).eq(aliceBefore.add(gross).sub(gasCost)), + "claimant != +gross after unlock" + ); + assert.isTrue((await queue.totalEscrowed(ZERO_ADDRESS)).eq(toBN(0))); + }); + + it("block-trap: a frozen claimant cannot execute the escrowed claim", async () => { + await wireQueue(); + await setupSurplus(alice); + await borrowerOperations.claimCollateral({ from: alice }); + await th.fastForwardTime(DELAY + 1, web3.currentProvider); + await queue.freeze(alice); + + await th.assertRevert(queue.executeExit(1, { from: alice }), "MockQueue: actor blocked"); + }); +}); diff --git a/tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json b/tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json index 9a2c2a6..49d6d89 100644 --- a/tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json +++ b/tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json @@ -1,8 +1,8 @@ { "_meta": { - "purpose": "Storage-layout zero-diff baseline for the Zero surplus-claim exit fee.", + "purpose": "Storage-layout zero-diff baseline for the Zero surplus-claim exit fee AND the security-perimeter delay hooks.", "baseRef": "sovryn-perimeter-fee @ b6584a6", - "note": "Normalized solc storageLayout (AST id suffixes after ')' stripped) for the upgradeable BorrowerOperations and CollSurplusPool proxies plus ActivePool, captured from the UNMODIFIED b6584a6 tree, before the surplus-claim fee hook was applied. tests-perimeter/StorageLayout.zerodiff.test.js asserts the current tree's layout is identical — proving the hook appends NO state. Regenerate only on an intentional, reviewed layout change (see the test header).", + "note": "Normalized solc storageLayout (AST id suffixes after ')' stripped) for the upgradeable BorrowerOperations and CollSurplusPool proxies plus ActivePool, captured from the UNMODIFIED b6584a6 tree, before the surplus-claim fee hook and before the exit-delay hooks were applied. tests-perimeter/StorageLayout.zerodiff.test.js asserts the current tree's layout is identical \u2014 proving neither hook appends state (the controller and queue pointers live in EIP-1967 unstructured slots). Regenerate only on an intentional, reviewed layout change (see the test header).", "consumers": [ "tests-perimeter/StorageLayout.zerodiff.test.js", "tests-perimeter/utils/storageLayout.js" diff --git a/tests-perimeter/utils/storageLayout.js b/tests-perimeter/utils/storageLayout.js index 124f12e..0533fda 100644 --- a/tests-perimeter/utils/storageLayout.js +++ b/tests-perimeter/utils/storageLayout.js @@ -13,10 +13,10 @@ const hre = require("hardhat"); const normType = (t) => (typeof t === "string" ? t.replace(/\)[0-9]+/g, ")") : t); // Return a stable, comparable array of {label, slot, offset, type} for the -// contract's declared state variables. Throws (never silently empties) if the -// layout is missing/empty — an empty layout compared to an empty layout is a -// silent false PASS, which would make this guard useless. -async function normalizedLayout(fqName) { +// contract's declared state variables. Throws if the layout is missing, but +// ALLOWS an empty one: a contract that declares no storage is a real and +// checkable property (the delegatecall companion depends on it). +async function rawLayout(fqName) { const bi = await hre.artifacts.getBuildInfo(fqName); if (!bi) throw new Error(`no build-info for ${fqName} (compile with storageLayout enabled)`); const [source, name] = fqName.split(":"); @@ -26,11 +26,6 @@ async function normalizedLayout(fqName) { if (!layout || !Array.isArray(layout.storage)) { throw new Error(`no storageLayout for ${fqName} — is "storageLayout" in outputSelection?`); } - if (layout.storage.length === 0) { - throw new Error( - `${fqName} storageLayout has ZERO entries — refusing to treat as zero-diff (silent false pass)` - ); - } return layout.storage .map((s) => ({ label: s.label, @@ -46,4 +41,17 @@ async function normalizedLayout(fqName) { ); } -module.exports = { normalizedLayout, normType }; +// Same as `rawLayout`, but refuses an empty layout: comparing an empty layout +// against an empty baseline is a silent false PASS, which would make the +// zero-diff and append-only guards useless. +async function normalizedLayout(fqName) { + const layout = await rawLayout(fqName); + if (layout.length === 0) { + throw new Error( + `${fqName} storageLayout has ZERO entries — refusing to treat as zero-diff (silent false pass)` + ); + } + return layout; +} + +module.exports = { normalizedLayout, rawLayout, normType }; diff --git a/utils/js/deploymentHelpers.js b/utils/js/deploymentHelpers.js index bc2b1b3..e0c6e7f 100644 --- a/utils/js/deploymentHelpers.js +++ b/utils/js/deploymentHelpers.js @@ -13,6 +13,9 @@ const GasPool = artifacts.require("./GasPool.sol"); const CollSurplusPool = artifacts.require("./CollSurplusPool.sol"); const FunctionCaller = artifacts.require("./TestContracts/FunctionCaller.sol"); const BorrowerOperations = artifacts.require("./BorrowerOperations.sol"); +const BorrowerOperationsPerimeterOps = artifacts.require( + "./Dependencies/BorrowerOperationsPerimeterOps.sol" +); const HintHelpers = artifacts.require("./HintHelpers.sol"); const FeeDistributor = artifacts.require("./FeeDistributor.sol"); @@ -114,6 +117,9 @@ class DeploymentHelper { const collSurplusPool = await CollSurplusPool.new(); const functionCaller = await FunctionCaller.new(); const borrowerOperations = await BorrowerOperations.new(permit2.address); + await borrowerOperations.setPerimeterOps( + (await BorrowerOperationsPerimeterOps.new()).address + ); const hintHelpers = await HintHelpers.new(); const zusdToken = await ZUSDToken.new(); const feeDistributor = await FeeDistributor.new(); @@ -279,6 +285,9 @@ class DeploymentHelper { const collSurplusPool = await CollSurplusPool.new(); const functionCaller = await FunctionCaller.new(); const borrowerOperations = await BorrowerOperations.new(permit2.address); + await borrowerOperations.setPerimeterOps( + (await BorrowerOperationsPerimeterOps.new()).address + ); const hintHelpers = await HintHelpers.new(); const zusdToken = await ZUSDToken.new(); const feeDistributor = await FeeDistributor.new();