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
73 changes: 72 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,75 @@
## Stake Exchange AMM
![Valantis](img/Valantis_Banner.png)

## Valantis Stake Exchange AMM (STEX AMM)

STEX AMM is a novel AMM uniquely designed for redeemable assets such as Liquid Staking Tokens (LSTs), designed in collaboration with [Thunderhead](https://thunderhead.xyz/).

LSTs are backed 1:1 by an equivalent amount of native asset (in the absence of slashing). However, generic AMMs fail to account for this simple fact, forcing LPs to sell the LST for less than fair value, resulting in significant cumulative losses to arbitrageurs. Moreover, there are times where excess liquidity can be put to earn extra yield on external protocols (e.g. lending markets like AAVE and Euler) and only be brought back into the AMM if needed to absorb incoming swap volume.

STEX AMM solves these two structural inefficiencies by integrating with the LST's protocol native withdrawal queue, hence converting any desired about of LST back into native token at 1:1 rate after a waiting period (e.g. 1-7 days on HyperEVM). Moreover, a portion of native token's unused reserves can be put to earn yield on a lending market. Swap fees are dynamic, going as low as 1 basis-point, and growing higher depending on how congested the LST protocol's withdrawal queue is, providing attractive exchange rates for swaps with clearly defined pricing bounds.

- [Docs](https://docs.valantis.xyz/staked-amm)
- [Whitepaper](https://github.com/ValantisLabs/stex-amm-whitepaper/blob/main/STEX_AMM_WHITEPAPER.pdf)

## Folder structure description

### src/

Contains STEX AMM's core contracts, Module dependencies and Mock contracts used for testing.

**AaveLendingModule.sol**: This is a dedicated module, compatible with AAVE V3's `supply` and `withdraw` functions. Its owner can deposit and withdraw a portion of Wrapped Native Token's pool reserves, with the goal of optimizing overall yield.

**STEXAMM.sol**: The main contract which implements the core mechanisms of STEX AMM, built as a Valantis [Liquidity Module](https://docs.valantis.xyz/sovereign-pool-subpages/modules/liquidity-module).

**STEXLens.sol**: Helper contract that contains read-only functions which are useful to simulate state updates in `STEXAMM`.

**STEXRatioSwapFeeModule.sol**: Contains a dynamic fee mechanism for swaps on STEX AMM, built as a Valantis [Swap Fee Module](https://docs.valantis.xyz/sovereign-pool-subpages/modules/swap-fee-module).

**stHYPEWithdrawalModule.sol**: Module that manages all of STEX AMM's interactions with [stakedHYPE](https://www.stakedhype.fi/), a leading LST protocol on HyperEVM developed by [Thunderhead](https://thunderhead.xyz/).

**owner/WithdrawalModuleManager.sol\***: Custom contract that has the `owner` role in `stHYPEWithdrawalModule`. It is controlled by a multi-sig.

**owner/WithdrawalModuleKeeper.sol**: A sub-role in `WithdrawalModuleManager`, executing smart contract calls that require automation but which are not mission critical.

**interfaces/**: Contains all relevant interfaces.

**structs/**: Contains all relevant structs.

**mocks/**: Contains mock contracts required for testing.

### test/

Contains the foundry tests.

### scripts/

Contains the scripts to deploy STEX AMM and all its respective module dependencies, execute swaps, deposits or withdrawals, and update specific parameters of the modules.

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Test coverage

```shell
$ bash coverage.sh
```

### Deploy

Copy .env.example file to .env and set the variables.

**Note:** All deployment bash scripts are, by default, in simulation mode. Add `--broadcast` flag to trigger deployments, and `--verify` for block explorer contract verification.

### License

Expand Down
Binary file added img/Valantis_Banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 34 additions & 9 deletions scripts/LendingModuleProposal.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ contract LendingModuleProposalScript is Script, Test {
function run() external {
if (block.chainid != 999) revert("Chain ID not Hyper EVM mainnet");

console.log("Deployer address: ", deployerAddress);

// Address of owner multi-sig wallet
address ownerMultisig = 0xe26dA5cBf101bDA4028E2B3208c32424f5D09421;

Expand Down Expand Up @@ -59,28 +57,28 @@ contract LendingModuleProposalScript is Script, Test {
// Simulate proposal
assertEq(lendingModule.assetBalance(), 0);

/*vm.startPrank(address(manager));
withdrawalModule.proposeLendingModule(address(lendingModule), 3 days);
//vm.startPrank(address(manager));
/*withdrawalModule.proposeLendingModule(address(lendingModule), 3 days);
(
address lendingModuleProposed,
uint256 startTimestamp
) = withdrawalModule.lendingModuleProposal();
assertEq(lendingModuleProposed, address(lendingModule));
assertEq(startTimestamp, block.timestamp + 3 days);

vm.warp(block.timestamp + 3 days);
vm.warp(block.timestamp + 3 days);*/

withdrawalModule.setProposedLendingModule();
/*withdrawalModule.setProposedLendingModule();
assertEq(
address(withdrawalModule.lendingModule()),
address(lendingModule)
);

withdrawalModule.supplyToken1ToLendingPool(10 ether);
assertEq(lendingModule.assetBalance(), 10 ether);
vm.stopPrank();*/
assertEq(lendingModule.assetBalance(), 10 ether);*/
//vm.stopPrank();

// Generate payload for proposal
// Generate payload for `proposeLendingModule`
/*vm.startPrank(ownerMultisig);

bytes memory payload = abi.encodeWithSelector(
Expand All @@ -106,5 +104,32 @@ contract LendingModuleProposalScript is Script, Test {
assertEq(startTimestamp, block.timestamp + 3 days);

vm.stopPrank();*/

// Generate payload for `setProposedLendingModule`
vm.startPrank(ownerMultisig);

bytes memory payload = abi.encodeWithSelector(
stHYPEWithdrawalModule.setProposedLendingModule.selector
);
bytes memory managerPayload = abi.encodeWithSelector(
WithdrawalModuleManager.call.selector,
address(withdrawalModule),
payload
);
console.log("payload to withdrawalModule manager: ");
console.logBytes(managerPayload);

(bool success, ) = address(manager).call(managerPayload);
assertTrue(success);

assertEq(
address(withdrawalModule.lendingModule()),
address(lendingModule)
);

vm.stopPrank();

//withdrawalModule.supplyToken1ToLendingPool(10 ether);
//assertEq(lendingModule.assetBalance(), 10 ether);
}
}
Loading