Skip to content

Instantly share code, notes, and snippets.

@mudgen
Last active October 25, 2024 22:41
Show Gist options
  • Save mudgen/7d50e3d0aca93b9cc321dfa0dbded373 to your computer and use it in GitHub Desktop.
Save mudgen/7d50e3d0aca93b9cc321dfa0dbded373 to your computer and use it in GitHub Desktop.
Static Diamond by Pendle
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.17;
// Static Diamond
// A static implementation of EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
// This code was extraced from Pendle's deployed contracts here:
// https://etherscan.io/address/0x0000000001e4ef00d069e71d6ba041b0a16f7ea0#code#F1#L1
// Blog article on the basics to implement EIP-2535 Diamonds here:
// https://eip2535diamonds.substack.com/p/simplicity-of-eip-2535-diamonds-standard
import "../interfaces/IDiamondLoupe.sol";
import "../interfaces/IDiamondCut.sol";
// solhint-disable no-empty-blocks
contract PendleRouter is Proxy, IDiamondLoupe {
address internal immutable ACTION_MINT_REDEEM;
address internal immutable ACTION_ADD_REMOVE_LIQ;
address internal immutable ACTION_SWAP_PT;
address internal immutable ACTION_SWAP_YT;
address internal immutable ACTION_MISC;
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
constructor(
address _ACTION_MINT_REDEEM,
address _ACTION_ADD_REMOVE_LIQ,
address _ACTION_SWAP_PT,
address _ACTION_SWAP_YT,
address _ACTION_MISC
) {
ACTION_MINT_REDEEM = _ACTION_MINT_REDEEM;
ACTION_ADD_REMOVE_LIQ = _ACTION_ADD_REMOVE_LIQ;
ACTION_SWAP_PT = _ACTION_SWAP_PT;
ACTION_SWAP_YT = _ACTION_SWAP_YT;
ACTION_MISC = _ACTION_MISC;
_emitEvent();
}
function _emitEvent() internal {
Facet[] memory facets_ = facets();
uint256 nFacets = facets_.length;
IDiamondCut.FacetCut[] memory cuts = new IDiamondCut.FacetCut[](nFacets);
for (uint256 i; i < nFacets; ) {
cuts[i].facetAddress = facets_[i].facetAddress;
cuts[i].action = IDiamondCut.FacetCutAction.Add;
cuts[i].functionSelectors = facets_[i].functionSelectors;
unchecked {
++i;
}
}
emit DiamondCut(cuts, address(0), "");
}
/// @notice Gets all facet addresses and their four byte function selectors.
/// @return facets_ Facet
function facets() public view returns (Facet[] memory facets_) {
address[] memory facetAddresses_ = facetAddresses();
uint256 numFacets = facetAddresses_.length;
facets_ = new Facet[](numFacets);
for (uint256 i; i < numFacets; ) {
facets_[i].facetAddress = facetAddresses_[i];
facets_[i].functionSelectors = facetFunctionSelectors(facetAddresses_[i]);
unchecked {
i++;
}
}
}
function facetFunctionSelectors(address facet) public view returns (bytes4[] memory res) {
if (facet == ACTION_ADD_REMOVE_LIQ) {
res = new bytes4[](12);
res[0] = 0x97ee279e; // addLiquidityDualSyAndPt
res[1] = 0xcb591eb2; // addLiquidityDualTokenAndPt
res[2] = 0x3af1f329; // addLiquiditySinglePt
res[3] = 0x409c7a89; // addLiquiditySingleSy
res[4] = 0x015491d1; // addLiquiditySingleToken
res[5] = 0xb7d75b8b; // removeLiquidityDualSyAndPt
res[6] = 0xe6eaba01; // removeLiquidityDualTokenAndPt
res[7] = 0x694ab559; // removeLiquiditySinglePt
res[8] = 0x178d29d3; // removeLiquiditySingleSy
res[9] = 0x690807ad; // removeLiquiditySingleToken
res[10] = 0xdfbc814e; // addLiquiditySingleTokenKeepYt
res[11] = 0x844384aa; // addLiquiditySingleSyKeepYt
return res;
}
if (facet == ACTION_MINT_REDEEM) {
res = new bytes4[](7);
res[0] = 0x1a8631b2; // mintPyFromSy
res[1] = 0x46eb2db6; // mintPyFromToken
res[2] = 0x443e6512; // mintSyFromToken
res[3] = 0xf7e375e8; // redeemDueInterestAndRewards
res[4] = 0x339748cb; // redeemPyToSy
res[5] = 0x527df199; // redeemPyToToken
res[6] = 0x85b29936; // redeemSyToToken
return res;
}
if (facet == ACTION_SWAP_PT) {
res = new bytes4[](6);
res[0] = 0x2032aecd; // swapExactPtForSy
res[1] = 0xb85f50ba; // swapExactPtForToken
res[2] = 0x83c71b69; // swapExactSyForPt
res[3] = 0xa5f9931b; // swapExactTokenForPt
res[4] = 0xdd371acd; // swapPtForExactSy
res[5] = 0x6b8bdf32; // swapSyForExactPt
return res;
}
if (facet == ACTION_SWAP_YT) {
res = new bytes4[](9);
res[0] = 0xfa483e72; // swapCallback
res[1] = 0xc861a898; // swapExactPtForYt
res[2] = 0x448b9b95; // swapExactYtForPt
res[3] = 0xfdd71f43; // swapExactSyForYt
res[4] = 0xc4a9c7de; // swapExactTokenForYt
res[5] = 0x357d6540; // swapExactYtForSy
res[6] = 0xd6308fa4; // swapExactYtForToken
res[7] = 0xbf1bd434; // swapSyForExactYt
res[8] = 0xe15cc098; // swapYtForExactSy
return res;
}
if (facet == ACTION_MISC) {
res = new bytes4[](2);
res[0] = 0xacdb32df; // approveInf
res[1] = 0xd617b03b; // batchExec
return res;
}
if (facet == address(this)) {
res = new bytes4[](4);
res[0] = 0xcdffacc6; // facetAddress
res[1] = 0x52ef6b2c; // facetAddresses
res[2] = 0xadfca15e; // facetFunctionSelectors
res[3] = 0x7a0ed627; // facets
return res;
}
revert Errors.RouterInvalidFacet(facet);
}
function facetAddress(bytes4 sig) public view returns (address) {
if (sig < 0x97ee279e) {
if (sig < 0x46eb2db6) {
if (sig < 0x357d6540) {
if (sig < 0x1a8631b2) {
if (sig == 0x015491d1) return ACTION_ADD_REMOVE_LIQ; // addLiquiditySingleToken 5
if (sig == 0x178d29d3) return ACTION_ADD_REMOVE_LIQ; // removeLiquiditySingleSy 6
} else {
if (sig == 0x1a8631b2) return ACTION_MINT_REDEEM; // mintPyFromSy 5
if (sig == 0x2032aecd) return ACTION_SWAP_PT; // swapExactPtForSy 6
if (sig == 0x339748cb) return ACTION_MINT_REDEEM; // redeemPyToSy 7
}
} else {
if (sig < 0x409c7a89) {
if (sig == 0x357d6540) return ACTION_SWAP_YT; // swapExactYtForSy 5
if (sig == 0x3af1f329) return ACTION_ADD_REMOVE_LIQ; // addLiquiditySinglePt 6
} else {
if (sig == 0x409c7a89) return ACTION_ADD_REMOVE_LIQ; // addLiquiditySingleSy 5
if (sig == 0x443e6512) return ACTION_MINT_REDEEM; // mintSyFromToken 6
if (sig == 0x448b9b95) return ACTION_SWAP_YT; // swapExactYtForPt 7
}
}
} else {
if (sig < 0x6b8bdf32) {
if (sig < 0x52ef6b2c) {
if (sig == 0x46eb2db6) return ACTION_MINT_REDEEM; // mintPyFromToken 5
if (sig == 0x527df199) return ACTION_MINT_REDEEM; // redeemPyToToken 6
} else {
if (sig == 0x690807ad) return ACTION_ADD_REMOVE_LIQ; // removeLiquiditySingleToken 5
if (sig == 0x694ab559) return ACTION_ADD_REMOVE_LIQ; // removeLiquiditySinglePt 6
if (sig == 0x52ef6b2c) return address(this); // facetAddresses 7
}
} else {
if (sig < 0x83c71b69) {
if (sig == 0x6b8bdf32) return ACTION_SWAP_PT; // swapSyForExactPt 5
if (sig == 0x7a0ed627) return address(this); // facets 6
} else {
if (sig == 0x85b29936) return ACTION_MINT_REDEEM; // redeemSyToToken 5
if (sig == 0x844384aa) return ACTION_ADD_REMOVE_LIQ; // addLiquiditySingleSyKeepYt 6
if (sig == 0x83c71b69) return ACTION_SWAP_PT; // swapExactSyForPt 7
}
}
}
} else {
if (sig < 0xcdffacc6) {
if (sig < 0xb85f50ba) {
if (sig < 0xacdb32df) {
if (sig == 0xa5f9931b) return ACTION_SWAP_PT; // swapExactTokenForPt 5
if (sig == 0x97ee279e) return ACTION_ADD_REMOVE_LIQ; // addLiquidityDualSyAndPt 6
} else {
if (sig == 0xb7d75b8b) return ACTION_ADD_REMOVE_LIQ; // removeLiquidityDualSyAndPt 5
if (sig == 0xacdb32df) return ACTION_MISC; // approveInf 6
if (sig == 0xadfca15e) return address(this); // facetFunctionSelectors 7
}
} else {
if (sig < 0xc4a9c7de) {
if (sig == 0xb85f50ba) return ACTION_SWAP_PT; // swapExactPtForToken 5
if (sig == 0xbf1bd434) return ACTION_SWAP_YT; // swapSyForExactYt 6
} else {
if (sig == 0xc4a9c7de) return ACTION_SWAP_YT; // swapExactTokenForYt 5
if (sig == 0xcb591eb2) return ACTION_ADD_REMOVE_LIQ; // addLiquidityDualTokenAndPt 6
if (sig == 0xc861a898) return ACTION_SWAP_YT; // swapExactPtForYt 7
}
}
} else {
if (sig < 0xe15cc098) {
if (sig < 0xd6308fa4) {
if (sig == 0xd617b03b) return ACTION_MISC; // batchExec 5
if (sig == 0xcdffacc6) return address(this); // facetAddress 6
} else {
if (sig == 0xd6308fa4) return ACTION_SWAP_YT; // swapExactYtForToken 5
if (sig == 0xdfbc814e) return ACTION_ADD_REMOVE_LIQ; // addLiquiditySingleTokenKeepYt 6
if (sig == 0xdd371acd) return ACTION_SWAP_PT; // swapPtForExactSy 7
}
} else {
if (sig < 0xf7e375e8) {
if (sig == 0xe6eaba01) return ACTION_ADD_REMOVE_LIQ; // removeLiquidityDualTokenAndPt 5
if (sig == 0xe15cc098) return ACTION_SWAP_YT; // swapYtForExactSy 6
} else {
if (sig == 0xfa483e72) return ACTION_SWAP_YT; // swapCallback 5
if (sig == 0xf7e375e8) return ACTION_MINT_REDEEM; // redeemDueInterestAndRewards 6
if (sig == 0xfdd71f43) return ACTION_SWAP_YT; // swapExactSyForYt 7
}
}
}
}
revert Errors.RouterInvalidAction(sig);
// NUM_FUNC: 40 AVG:5.80 STD:0.75 WORST_CASE:7 STOP_BRANCH:3
}
function facetAddresses() public view returns (address[] memory) {
address[] memory res = new address[](6);
res[0] = ACTION_ADD_REMOVE_LIQ;
res[1] = ACTION_MINT_REDEEM;
res[2] = ACTION_SWAP_PT;
res[3] = ACTION_SWAP_YT;
res[4] = ACTION_MISC;
res[5] = address(this);
return res;
}
function _implementation() internal view override returns (address) {
return facetAddress(msg.sig);
}
}
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment