Skip to content

Commit

Permalink
fix: tenderize pool params
Browse files Browse the repository at this point in the history
  • Loading branch information
kyriediculous committed Apr 14, 2024
1 parent 3ce7501 commit e2abc1e
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 53 deletions.
14 changes: 7 additions & 7 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fuzz = { runs = 1_000 }
gas_reports = ["*"]
libs = ["lib"]
# optimizer = true (default)
optimizer_runs = 100
optimizer_runs = 200
fs_permissions = [{ access = "read-write", path = "./" }]
solc = "0.8.20"

Expand All @@ -23,25 +23,25 @@ quote_style = "double"
tab_width = 4
wrap_comments = true

# [etherscan]
# arbitrum_one = { key = "${API_KEY_ARBISCAN}" }
[etherscan]
arbitrum_one = { key = "${API_KEY_ARBISCAN}" }
# avalanche = { key = "${API_KEY_SNOWTRACE}" }
# bnb_smart_chain = { key = "${API_KEY_BSCSCAN}" }
# gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" }
# goerli = { key = "${API_KEY_ETHERSCAN}" }
# mainnet = { key = "${API_KEY_ETHERSCAN}" }
mainnet = { key = "${API_KEY_ETHERSCAN}" }
# optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" }
# polygon = { key = "${API_KEY_POLYGONSCAN}" }
# sepolia = { key = "${API_KEY_ETHERSCAN}" }

# [rpc_endpoints]
# arbitrum_one = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
[rpc_endpoints]
arbitrum_one = "https://arb-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
# avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}"
# bnb_smart_chain = "https://bsc-dataseed.binance.org"
# gnosis_chain = "https://rpc.gnosischain.com"
# goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}"
# localhost = "http://localhost:8545"
# mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
# optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
# polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}"
# sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
},
"private": true,
"scripts": {
"clean": "rm -rf cache out",
"clean": "rm -rf cache out broadcast",
"lint": "yarn lint:sol && yarn prettier:write",
"lint:sol": "forge fmt && yarn solhint src/**/*.sol",
"prettier:check": "prettier --check **/*.{json,md,yml} --ignore-path=.prettierignore",
"prettier:write": "prettier --write **/*.{json,md,yml} --ignore-path=.prettierignore"
}
}
}
12 changes: 10 additions & 2 deletions script/Swap_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { SwapFactory } from "@tenderize/swap/Factory.sol";
import { UD60x18 } from "@prb/math/UD60x18.sol";
import { ERC1967Proxy } from "openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol";

// TENDERIZE POOLS BASE FEE = 0.025% with K=4
// EXOTIC POOLS BASE FEE = 0.1% with K=4

address constant FACTORY = address(0);

contract Swap_Deploy is Script {
Expand All @@ -19,9 +22,14 @@ contract Swap_Deploy is Script {
// Start broadcasting with private key from `.env` file
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address underlying = vm.envAddress("UNDERLYING");
UD60x18 BASE_FEE = UD60x18.wrap(vm.envUint("BASE_FEE"));
UD60x18 K = UD60x18.wrap(vm.envUint("K"));

// TENDERIZE POOLS
UD60x18 BASE_FEE = UD60x18.wrap(0.0005e18); // 0.05%
UD60x18 K = UD60x18.wrap(5e18);

// EXOTIC POOLS
// UD60x18 BASE_FEE = UD60x18.wrap(0.001e18); // 0.1%
// UD60x18 K = UD60x18.wrap(4e18);
ConstructorConfig cfg = ConstructorConfig({ UNDERLYING: ERC20(underlying), BASE_FEE: BASE_FEE, K: K });

function run() public {
Expand Down
80 changes: 38 additions & 42 deletions src/Swap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ contract TenderSwap is Initializable, UUPSUpgradeable, OwnableUpgradeable, SwapS
UD60x18 public immutable K;

// Minimum cut of the fee for LPs when an unlock is bought
UD60x18 public constant MIN_LP_CUT = UD60x18.wrap(0.05e18);
UD60x18 public constant MIN_LP_CUT = UD60x18.wrap(0.1e18); // 10%
// Cut of the fee for the treasury when an unlock is bought or redeemed
UD60x18 public constant TREASURY_CUT = UD60x18.wrap(0.01e18);
UD60x18 public constant TREASURY_CUT = UD60x18.wrap(0.1e18); // 10%
// Cut of the fee for the relayer when an unlock is redeemed
UD60x18 public constant RELAYER_CUT = UD60x18.wrap(0.01e18);
UD60x18 public constant RELAYER_CUT = UD60x18.wrap(0.025e18); // 2.5%

function initialize() public initializer {
Data storage $ = _loadStorageSlot();
Expand Down Expand Up @@ -504,55 +504,51 @@ contract TenderSwap is Initializable, UUPSUpgradeable, OwnableUpgradeable, SwapS

function _quote(uint256 amount, SwapParams memory p) internal view returns (uint256 out, uint256 fee) {
Data storage $ = _loadStorageSlot();
UD60x18 x = ud(amount);
UD60x18 nom = _calculateNominator(x, p, $);
UD60x18 denom = _calculateDenominator(p);

UD60x18 x = ud((amount));
UD60x18 L = ud(($.liabilities));
UD60x18 nom;
UD60x18 denom;

// (((u + x)*k - U + u)*((U + x)/L)**k + (-k*u + U - u)*(U/L)**k)*(S + U)/(k*(1 + k)*(s + u))

// in this formula (-k*u + U -u) can be rewritten as U-(k+1)*u
// if U < (k+1*u) then we must do (k+1)*u - U and subtract that from the first part of the sum in the nominator
// else we use the initial formula

{
UD60x18 sumA = p.u.add(x).mul(K).add(p.u);
UD60x18 negatorB = K.add(UNIT_60x18).mul(p.u);

if (sumA < p.U) {
sumA = p.U.sub(sumA).mul(p.U.add(x).div(L).pow(K));
// we must subtract sumA from sumB
// we know sumB must always be positive so we
// can proceed with the regular calculation
UD60x18 sumB = p.U.sub(negatorB).mul(p.U.div(L).pow(K));
nom = sumB.sub(sumA).mul(p.S.add(p.U));
} else {
// sumA is positive, sumB can be positive or negative
sumA = sumA.sub(p.U).mul(p.U.add(x).div(L).pow(K));
if (p.U < negatorB) {
UD60x18 sumB = negatorB.sub(p.U).mul(p.U.div(L).pow(K));
nom = sumA.sub(sumB).mul(p.S.add(p.U));
} else {
UD60x18 sumB = p.U.sub(negatorB).mul(p.U.div(L).pow(K));
nom = sumA.add(sumB).mul(p.S.add(p.U));
}
}

denom = K.mul(UNIT_60x18.add(K)).mul(p.s.add(p.u));
}
UD60x18 baseFee = BASE_FEE.mul(x);
fee = baseFee.add(nom.div(denom)).unwrap();

fee = BASE_FEE.mul(x).add(nom.div(denom)).unwrap();
fee = fee >= amount ? amount : fee;
unchecked {
out = amount - fee;
}
}

function _calculateNominator(UD60x18 x, SwapParams memory p, Data storage $) internal view returns (UD60x18 nom) {
UD60x18 L = ud($.liabilities);
UD60x18 sumA = p.u.add(x).mul(K).add(p.u);
UD60x18 negatorB = K.add(UNIT_60x18).mul(p.u);
UD60x18 util = p.U.div(L).pow(K);
UD60x18 util_change = p.U.add(x).div(L).pow(K);

if (sumA < p.U) {
sumA = p.U.sub(sumA).mul(util_change);
// we must subtract sumA from sumB
// we know sumB must always be positive so we
// can proceed with the regular calculation
UD60x18 sumB = p.U.sub(negatorB).mul(util);
nom = sumB.sub(sumA).mul(p.S.add(p.U));
} else {
// sumA is positive, sumB can be positive or negative
sumA = sumA.sub(p.U).mul(util_change);
if (p.U < negatorB) {
UD60x18 sumB = negatorB.sub(p.U).mul(util);
nom = sumA.sub(sumB).mul(p.S.add(p.U));
} else {
UD60x18 sumB = p.U.sub(negatorB).mul(util);
nom = sumA.add(sumB).mul(p.S.add(p.U));
}
}
}

function _calculateDenominator(SwapParams memory p) internal view returns (UD60x18) {
return K.mul(UNIT_60x18.add(K)).mul(p.s.add(p.u));
}
/**
* @notice checks if an asset is a valid tenderizer for `UNDERLYING`
*/

function _isValidAsset(address asset) internal view returns (bool) {
return REGISTRY.isTenderizer(asset) && Tenderizer(asset).asset() == address(UNDERLYING);
}
Expand Down

0 comments on commit e2abc1e

Please sign in to comment.