Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 44 additions & 44 deletions .gas-snapshot.runtime
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorAndProtocolFeeFill() (gas: 129374)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorFillAskFullyMatchesSingleBid() (gas: 103768)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorFillBidFullyMatchesSingleAsk() (gas: 103888)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorAndProtocolFeeFill() (gas: 129346)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorFillAskFullyMatchesSingleBid() (gas: 103757)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorFillBidFullyMatchesSingleAsk() (gas: 103866)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorFillRestBidEmptyBook() (gas: 151809)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorRouteNetsRepeatedFeeToken() (gas: 122504)
RadixMatchingEngineFeeGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 39664)
RadixMatchingEngineFeeGasTest:testGas_CancelFilledBidClaim() (gas: 36750)
DeepstateV1IntegratorFeeGasTest:testGas_IntegratorRouteNetsRepeatedFeeToken() (gas: 122482)
RadixMatchingEngineFeeGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 39659)
RadixMatchingEngineFeeGasTest:testGas_CancelFilledBidClaim() (gas: 36739)
RadixMatchingEngineFeeGasTest:testGas_CancelFullDepthBidCombRightmost() (gas: 423078)
RadixMatchingEngineFeeGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 424771)
RadixMatchingEngineFeeGasTest:testGas_CancelPartialBid() (gas: 48804)
RadixMatchingEngineFeeGasTest:testGas_CancelUnfilledAsk() (gas: 39881)
RadixMatchingEngineFeeGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 424760)
RadixMatchingEngineFeeGasTest:testGas_CancelPartialBid() (gas: 48797)
RadixMatchingEngineFeeGasTest:testGas_CancelUnfilledAsk() (gas: 39876)
RadixMatchingEngineFeeGasTest:testGas_CancelUnfilledBid() (gas: 39717)
RadixMatchingEngineFeeGasTest:testGas_FillAskConsumesDirtySamePriceBidSubtree() (gas: 87846)
RadixMatchingEngineFeeGasTest:testGas_FillAskConsumesFullDepthBidComb() (gas: 352999)
RadixMatchingEngineFeeGasTest:testGas_FillAskConsumesFullDepthBidComb() (gas: 352993)
RadixMatchingEngineFeeGasTest:testGas_FillAskFullyMatchesSingleBid() (gas: 78197)
RadixMatchingEngineFeeGasTest:testGas_FillAskPartiallyMatchesSingleBid() (gas: 97892)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 130838)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 87970)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 324094)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 77962)
RadixMatchingEngineFeeGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 77862)
RadixMatchingEngineFeeGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 97776)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 130827)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 87959)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 324083)
RadixMatchingEngineFeeGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 77951)
RadixMatchingEngineFeeGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 77851)
RadixMatchingEngineFeeGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 97765)
RadixMatchingEngineFeeGasTest:testGas_FillRestAskEmptyBook() (gas: 150894)
RadixMatchingEngineFeeGasTest:testGas_FillRestBidEmptyBook() (gas: 152651)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookAskMatchesOneBid() (gas: 122101)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 137302)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 138440)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 137291)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 138429)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookPartialFillsBid() (gas: 123225)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookRestsAsk() (gas: 163968)
RadixMatchingEngineFeeGasTest:testGas_LargeRandomBookRestsBid() (gas: 173286)
RadixMatchingEngineGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 39664)
RadixMatchingEngineGasTest:testGas_CancelFilledBidClaim() (gas: 36750)
RadixMatchingEngineGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 39659)
RadixMatchingEngineGasTest:testGas_CancelFilledBidClaim() (gas: 36739)
RadixMatchingEngineGasTest:testGas_CancelFullDepthBidCombRightmost() (gas: 423078)
RadixMatchingEngineGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 424751)
RadixMatchingEngineGasTest:testGas_CancelPartialBid() (gas: 48804)
RadixMatchingEngineGasTest:testGas_CancelUnfilledAsk() (gas: 39881)
RadixMatchingEngineGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 424740)
RadixMatchingEngineGasTest:testGas_CancelPartialBid() (gas: 48797)
RadixMatchingEngineGasTest:testGas_CancelUnfilledAsk() (gas: 39876)
RadixMatchingEngineGasTest:testGas_CancelUnfilledBid() (gas: 39717)
RadixMatchingEngineGasTest:testGas_FillAskConsumesDirtySamePriceBidSubtree() (gas: 87242)
RadixMatchingEngineGasTest:testGas_FillAskConsumesFullDepthBidComb() (gas: 327303)
RadixMatchingEngineGasTest:testGas_FillAskFullyMatchesSingleBid() (gas: 77593)
RadixMatchingEngineGasTest:testGas_FillAskPartiallyMatchesSingleBid() (gas: 97288)
RadixMatchingEngineGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 130241)
RadixMatchingEngineGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 87376)
RadixMatchingEngineGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 323500)
RadixMatchingEngineGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 77368)
RadixMatchingEngineGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 77268)
RadixMatchingEngineGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 97182)
RadixMatchingEngineGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 130230)
RadixMatchingEngineGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 87365)
RadixMatchingEngineGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 323489)
RadixMatchingEngineGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 77357)
RadixMatchingEngineGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 77257)
RadixMatchingEngineGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 97171)
RadixMatchingEngineGasTest:testGas_FillRestAskEmptyBook() (gas: 150668)
RadixMatchingEngineGasTest:testGas_FillRestBidEmptyBook() (gas: 152432)
RadixMatchingEngineGasTest:testGas_LargeRandomBookAskMatchesOneBid() (gas: 121497)
RadixMatchingEngineGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 136708)
RadixMatchingEngineGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 137846)
RadixMatchingEngineGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 136697)
RadixMatchingEngineGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 137835)
RadixMatchingEngineGasTest:testGas_LargeRandomBookPartialFillsBid() (gas: 122621)
RadixMatchingEngineGasTest:testGas_LargeRandomBookRestsAsk() (gas: 163742)
RadixMatchingEngineGasTest:testGas_LargeRandomBookRestsBid() (gas: 173067)
RadixMatchingEngineHookGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 43705)
RadixMatchingEngineHookGasTest:testGas_CancelFilledBidClaim() (gas: 37497)
RadixMatchingEngineHookGasTest:testGas_CancelAskSkipsPathologicalBidTree() (gas: 43698)
RadixMatchingEngineHookGasTest:testGas_CancelFilledBidClaim() (gas: 37486)
RadixMatchingEngineHookGasTest:testGas_CancelFullDepthBidCombRightmost() (gas: 446433)
RadixMatchingEngineHookGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 447267)
RadixMatchingEngineHookGasTest:testGas_CancelPartialBid() (gas: 53592)
RadixMatchingEngineHookGasTest:testGas_CancelUnfilledAsk() (gas: 43922)
RadixMatchingEngineHookGasTest:testGas_CancelMaxValidDepthAskCombRightmost() (gas: 447256)
RadixMatchingEngineHookGasTest:testGas_CancelPartialBid() (gas: 53587)
RadixMatchingEngineHookGasTest:testGas_CancelUnfilledAsk() (gas: 43915)
RadixMatchingEngineHookGasTest:testGas_CancelUnfilledBid() (gas: 44505)
RadixMatchingEngineHookGasTest:testGas_FillAskConsumesDirtySamePriceBidSubtree() (gas: 95252)
RadixMatchingEngineHookGasTest:testGas_FillAskConsumesFullDepthBidComb() (gas: 414778)
RadixMatchingEngineHookGasTest:testGas_FillAskFullyMatchesSingleBid() (gas: 85769)
RadixMatchingEngineHookGasTest:testGas_FillAskPartiallyMatchesSingleBid() (gas: 105472)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 139218)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 94243)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 410116)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 93348)
RadixMatchingEngineHookGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 84195)
RadixMatchingEngineHookGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 104117)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesAskAndRestsRemainder() (gas: 139207)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesDirtySamePriceAskSubtree() (gas: 94232)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesMaxValidDepthAskComb() (gas: 410105)
RadixMatchingEngineHookGasTest:testGas_FillBidConsumesSamePriceAskSubtree() (gas: 93337)
RadixMatchingEngineHookGasTest:testGas_FillBidFullyMatchesSingleAsk() (gas: 84184)
RadixMatchingEngineHookGasTest:testGas_FillBidPartiallyMatchesSingleAsk() (gas: 104106)
RadixMatchingEngineHookGasTest:testGas_FillRestAskEmptyBook() (gas: 140357)
RadixMatchingEngineHookGasTest:testGas_FillRestBidEmptyBook() (gas: 142118)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookAskMatchesOneBid() (gas: 138973)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 154786)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 146871)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookBidMatchesOneAsk() (gas: 154775)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookPartialFillsAsk() (gas: 146860)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookPartialFillsBid() (gas: 133256)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookRestsAsk() (gas: 193723)
RadixMatchingEngineHookGasTest:testGas_LargeRandomBookRestsBid() (gas: 198650)
18 changes: 12 additions & 6 deletions script/prove_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,17 @@ def bind_model_to_source():
"refund = msg.value - required;",
"_refundNativeValue(nativeRefund);",
"if (amount != 0) _safeTransferOut(address(0), msg.sender, amount);",
"_safeTransferOut(params.isBid ? params.token0 : params.token1, feeRecipient, feeAmount);",
"_safeTransferOut(outputToken, _configRecipient(protocolConfig), settlement.protocolFeeAmount);",
"_safeTransferProtocolFeeOut(params.isBid ? params.token0 : params.token1, feeRecipient, feeAmount);",
"_safeTransferProtocolFeeOut(outputToken, _configRecipient(protocolConfig), settlement.protocolFeeAmount);",
"_safeTransferOut(outputToken, integratorFee.recipient, settlement.integratorFeeAmount);",
"if (baseAmount != 0) _safeTransferOut(token0, owner, baseAmount);",
"_safeTransferOut(token, msg.sender, uint256(amount));",
"_safeTransferOut(token0, msg.sender, uint256(amount0));",
"if (amount != 0) _safeTransferProtocolFeeOut(token, recipient, amount);",
"if (amount != 0) _safeTransferOut(token, recipient, amount);",
"if iszero(lt(token0, token1)) {",
"if (token == address(0)) {",
"to.forceSafeTransferETH(amount);",
"to.safeTransferETH(amount);",
"if tload(_REENTRANCY_GUARD_SLOT) {",
"try IHook(hook).execute{gas: _HOOK_GAS_LIMIT}",
Expand All @@ -135,12 +137,16 @@ def bind_model_to_source():
if missing:
raise ProofFailure(f"production/model binding is stale; missing source fragment: {missing[0]}")

# Every native outflow must pass through the nine modelled call sites and the single transfer
# helper. A future direct ETH transfer or additional helper call must extend the proof first.
if source.count("_safeTransferOut(") != 10:
raise ProofFailure("production/model binding is stale; unexpected native-capable outflow site count")
# Every native outflow must pass through the nine modelled call sites and exactly one of the two
# transfer helpers. A future direct ETH transfer or additional helper call must extend the proof.
if source.count("_safeTransferOut(") != 7:
raise ProofFailure("production/model binding is stale; unexpected general outflow site count")
if source.count("_safeTransferProtocolFeeOut(") != 4:
raise ProofFailure("production/model binding is stale; unexpected protocol-fee outflow site count")
if source.count("safeTransferETH(") != 1:
raise ProofFailure("production/model binding is stale; unexpected direct native transfer count")
if source.count("forceSafeTransferETH(") != 1:
raise ProofFailure("production/model binding is stale; unexpected forced native transfer count")


def prove_tick_decomposition(p):
Expand Down
19 changes: 15 additions & 4 deletions src/DeepstateV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2237,7 +2237,7 @@ contract DeepstateV1 is Ownable {
}

/// @notice Configure protocol fees taken from taker output on matched quantity.
/// @param recipient Fee recipient. Zero disables fees and requires `bps == 0`.
/// @param recipient Fee recipient. Zero disables fees; native ETH fees cannot be rejected.
/// @param bps Fee in basis points, capped at 100.
function setFeeConfig(address recipient, uint16 bps) external onlyOwner {
if (bps > _MAX_FEE_BPS || (recipient == address(0) && bps != 0)) revert InvalidFeeConfig();
Expand Down Expand Up @@ -2315,7 +2315,7 @@ contract DeepstateV1 is Ownable {
assembly {
feeRecipient := config
}
_safeTransferOut(params.isBid ? params.token0 : params.token1, feeRecipient, feeAmount);
_safeTransferProtocolFeeOut(params.isBid ? params.token0 : params.token1, feeRecipient, feeAmount);
}
_refundNativeValue(nativeRefund);
}
Expand Down Expand Up @@ -2347,7 +2347,7 @@ contract DeepstateV1 is Ownable {
_settleDeltas(params.token0, settlement.token0Delta, params.token1, settlement.token1Delta);
address outputToken = params.isBid ? params.token0 : params.token1;
if (settlement.protocolFeeAmount != 0) {
_safeTransferOut(outputToken, _configRecipient(protocolConfig), settlement.protocolFeeAmount);
_safeTransferProtocolFeeOut(outputToken, _configRecipient(protocolConfig), settlement.protocolFeeAmount);
}
if (settlement.integratorFeeAmount != 0) {
_safeTransferOut(outputToken, integratorFee.recipient, settlement.integratorFeeAmount);
Expand Down Expand Up @@ -3154,7 +3154,7 @@ contract DeepstateV1 is Ownable {
tstore(slot, 0)
}

if (amount != 0) _safeTransferOut(token, recipient, amount);
if (amount != 0) _safeTransferProtocolFeeOut(token, recipient, amount);

unchecked {
++i;
Expand Down Expand Up @@ -3311,6 +3311,17 @@ contract DeepstateV1 is Ownable {
if (amount != 0) _safeTransferOut(address(0), msg.sender, amount);
}

/// @notice Pay an owner-configured protocol fee without letting an ETH receiver block fills.
/// @dev ERC20 settlement retains standard safe-transfer behavior. For native ETH, Solady first
/// attempts a bounded call and force-sends through an ephemeral contract if the recipient rejects.
function _safeTransferProtocolFeeOut(address token, address to, uint256 amount) private {
if (token == address(0)) {
to.forceSafeTransferETH(amount);
} else {
token.safeTransfer(to, amount);
}
}

/// @notice Pay either native ETH (`token == address(0)`) or an ERC20.
function _safeTransferOut(address token, address to, uint256 amount) private {
if (token == address(0)) {
Expand Down
Loading