diff --git a/contracts/JBXBuybackDelegate.sol b/contracts/JBXBuybackDelegate.sol
index 0ee751b..6a7b07f 100644
--- a/contracts/JBXBuybackDelegate.sol
+++ b/contracts/JBXBuybackDelegate.sol
@@ -89,6 +89,8 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
*/
IJBPayoutRedemptionPaymentTerminal3_1 public immutable jbxTerminal;
+ IJBDirectory private immutable directory;
+
/**
* @notice The WETH contract
*/
@@ -103,14 +105,14 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
*
* @dev This is a mutex 1-x-1
*/
- uint256 private mintedAmount = 1;
+ uint128 private mintedAmount = 1;
/**
* @notice The current reserved rate
*
* @dev This is a mutex 1-x-1
*/
- uint256 private reservedRate = 1;
+ uint128 private reservedRate = 1;
/**
* @dev No other logic besides initializing the immutables
@@ -124,6 +126,7 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
projectToken = _projectToken;
pool = _pool;
jbxTerminal = _jbxTerminal;
+ directory = jbxTerminal.directory();
_projectTokenIsZero = address(_projectToken) < address(_weth);
weth = _weth;
}
@@ -150,13 +153,22 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
uint256 _tokenCount = PRBMath.mulDiv(_data.amount.value, _data.weight, 10 ** 18);
// Unpack the quote from the pool, given by the frontend
- (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256));
+ uint256 _quote;
+ uint256 _slippage;
+ { // used to discard `data` variable and avoid extra stack manipulation
+ bytes calldata data = _data.metadata;
+ assembly {
+ _quote := calldataload(add(data.offset, 0x40))
+ _slippage := calldataload(add(data.offset, 0x60))
+ }
+ }
// If the amount swapped is bigger than the lowest received when minting, use the swap pathway
if (_tokenCount < _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR)) {
// Pass the quote and reserve rate via a mutex
- mintedAmount = _tokenCount;
- reservedRate = _data.reservedRate;
+ assembly {
+ sstore(mintedAmount.slot, or(shr(128, shl(128, _tokenCount)), shl(128, calldataload(0x164))))
+ }
// Return this delegate as the one to use, and do not mint from the terminal
delegateAllocations = new JBPayDelegateAllocation[](1);
@@ -182,18 +194,34 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
*/
function didPay(JBDidPayData calldata _data) external payable override {
// Access control as minting is authorized to this delegate
- if (msg.sender != address(jbxTerminal)) revert JuiceBuyback_Unauthorized();
+ IJBPayoutRedemptionPaymentTerminal3_1 _jbxTerminal = jbxTerminal;
+ assembly {
+ if xor(caller(), _jbxTerminal) {
+ // bytes4(keccak256("JuiceBuyback_Unauthorized()"))
+ mstore(0x00, 0x84f56813)
+ revert(0x1c, 0x04)
+ }
+ }
// Retrieve the number of token created if minting and reset the mutex (not exposed in JBDidPayData)
- uint256 _tokenCount = mintedAmount;
- mintedAmount = 1;
-
- // Retrieve the fc reserved rate and reset the mutex
- uint256 _reservedRate = reservedRate;
- reservedRate = 1;
+ uint256 _tokenCount;
+ uint256 _reservedRate;
+ assembly {
+ let storage_var := sload(mintedAmount.slot)
+ _tokenCount := shr(128, shl(128, storage_var))
+ _reservedRate := shr(128, storage_var)
+ sstore(mintedAmount.slot, or(1, shl(128, 1)))
+ }
// The minimum amount of token received if swapping
- (,, uint256 _quote, uint256 _slippage) = abi.decode(_data.metadata, (bytes32, bytes32, uint256, uint256));
+ uint256 _quote;
+ uint256 _slippage;
+ {
+ bytes calldata data = _data.metadata;
+ assembly {
+ _quote := calldataload(add(data.offset, 0x40))
+ _slippage := calldataload(add(data.offset, 0x60))
+ }
+ }
uint256 _minimumReceivedFromSwap = _quote - (_quote * _slippage / SLIPPAGE_DENOMINATOR);
// Pick the appropriate pathway (swap vs mint), use mint if non-claimed prefered
@@ -215,10 +243,19 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
*/
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override {
// Check if this is really a callback
- if (msg.sender != address(pool)) revert JuiceBuyback_Unauthorized();
+ IUniswapV3Pool _pool = pool;
+ assembly {
+ if xor(caller(), _pool) {
+ // bytes4(keccak256("JuiceBuyback_Unauthorized()"))
+ mstore(0x00, 0x84f56813)
+ revert(0x1c, 0x04)
+ }
+ }
// Unpack the data
- (uint256 _minimumAmountReceived) = abi.decode(data, (uint256));
+ uint256 _minimumAmountReceived;
+ assembly {
+ _minimumAmountReceived := calldataload(data.offset)
+ }
// Assign 0 and 1 accordingly
uint256 _amountReceived = uint256(-(_projectTokenIsZero ? amount0Delta : amount1Delta));
@@ -228,8 +265,19 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
if (_amountReceived < _minimumAmountReceived) revert JuiceBuyback_MaximumSlippage();
// Wrap and transfer the weth to the pool
- weth.deposit{value: _amountToSend}();
- weth.transfer(address(pool), _amountToSend);
+ IWETH9 _weth = weth;
+ assembly {
+ // function selectors for `deposit()` & `transfer(address,uint256)`
+ mstore(0x00, 0xd0e30db0a9059cbb)
+ if iszero(call(gas(), _weth, _amountToSend, 0x18, 0x04, 0x00, 0x00)) {revert(0, 0)}
+ // store memory pointer
+ let memptr := mload(0x40)
+ mstore(0x20, _pool)
+ mstore(0x40, _amountToSend)
+ if iszero(call(gas(), _weth, 0x00, 0x1c, 0x44, 0x00, 0x00)) {revert(0, 0)}
+ // restore memory pointer
+ mstore(0x40, memptr)
+ }
}
function redeemParams(JBRedeemParamsData calldata _data)
@@ -287,7 +335,7 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
// If there are reserved token, add them to the reserve
if (_reservedToken != 0) {
- IJBController controller = IJBController(jbxTerminal.directory().controllerOf(_data.projectId));
+ IJBController controller = IJBController(directory.controllerOf(_data.projectId));
// 1) Burn all the reserved token, which are in this address -> result: 0 here, 0 in reserve
controller.burnTokensOf({
@@ -322,7 +370,19 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
}
}
- emit JBXBuybackDelegate_Swap(_data.projectId, _data.amount.value, _amountReceived);
+ assembly {
+ let memptr := mload(0x40)
+ mstore(0x00, calldataload(0x44))
+ mstore(0x20, calldataload(0xa4))
+ mstore(0x40, _amountReceived)
+ log1(
+ 0x00,
+ 0x60,
+ // keccak256("JBXBuybackDelegate_Swap(uint256,uint256,uint256)")
+ 0x01a4fda29d012874ff22866f5058fa420a4f8598b6f5207b9851c577c11507f7
+ )
+ mstore(0x40, memptr)
+ }
}
/**
@@ -332,7 +392,7 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
* @param _amount the amount of token out to mint
*/
function _mint(JBDidPayData calldata _data, uint256 _amount) internal {
- IJBController controller = IJBController(jbxTerminal.directory().controllerOf(_data.projectId));
+ IJBController controller = IJBController(directory.controllerOf(_data.projectId));
// Mint to the beneficiary with the fc reserve rate
controller.mintTokensOf({
@@ -349,7 +409,15 @@ contract JBXBuybackDelegate is IJBFundingCycleDataSource, IJBPayDelegate, IUnisw
_data.projectId, _data.amount.value, JBTokens.ETH, "", new bytes(0)
);
- emit JBXBuybackDelegate_Mint(_data.projectId);
+ assembly {
+ mstore(0x00, calldataload(0x44))
+ log1(
+ 0x00,
+ 0x20,
+ // keccak256("JBXBuybackDelegate_Mint(uint256)")
+ 0x9dd9e06f6137ca3ab76ef60c229d956aa1d09df00d9f55800cec4e1d9cf21381
+ )
+ }
}
-
-
Save 0xJCN/28ddc1adcacdee9691ce126d23d7a1d6 to your computer and use it in GitHub Desktop.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment