Implement adapter and test templates
This commit is contained in:
@@ -15,7 +15,7 @@ Following exchanges have been integrated using VM approach:
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install [Foundry](https://book.getfoundry.sh/getting-started/installation#using-foundryup).
|
||||
1. Install [Foundry](https://book.getfoundry.sh/getting-started/installation#using-foundryup), start by downloading and installing the Foundry installer:
|
||||
```bash
|
||||
curl -L https://foundry.paradigm.xyz | bash
|
||||
```
|
||||
@@ -37,18 +37,27 @@ Following exchanges have been integrated using VM approach:
|
||||
|
||||
### Understanding the ISwapAdapter
|
||||
|
||||
1. Read the the documentation of the [Ethereum Solidity interface](ethereum-solidity.md). It describes the functions that need to be implemented as well as the manifest file.
|
||||
2. Additionally read through the docstring of the [ISwapAdapter.sol](../../../evm/src/interfaces/ISwapAdapter.sol) interface and the [ISwapAdapterTypes.sol](../../../evm/src/interfaces/ISwapAdapterTypes.sol) interface which defines the data types and errors used by the adapter interface.
|
||||
3. You can also generate the documentation locally and the look at the generated documentation in the `./docs` folder:
|
||||
Read the the documentation of the [Ethereum Solidity interface](ethereum-solidity.md). It describes the functions that need to be implemented as well as the manifest file.
|
||||
Additionally read through the docstring of the [ISwapAdapter.sol](../../../evm/src/interfaces/ISwapAdapter.sol) interface and the [ISwapAdapterTypes.sol](../../../evm/src/interfaces/ISwapAdapterTypes.sol) interface which defines the data types and errors used by the adapter interface.
|
||||
You can also generate the documentation locally and the look at the generated documentation in the `./docs` folder:
|
||||
```bash
|
||||
cd ./propeller-protocol-lib/evm/
|
||||
cd ./evm/
|
||||
forge doc
|
||||
```
|
||||
### Implementing the ISwapAdapter interface
|
||||
1. Your integration should be in a separate directory in the `evm/src` folder. Start by cloning the template directory:
|
||||
Your integration should be in a separate directory in the `evm/src` folder. Start by cloning the template directory:
|
||||
```bash
|
||||
cp -r ./evm/src/template ./evm/src/<your-adapter-name>
|
||||
cp ./evm/src/template ./evm/src/<your-adapter-name>
|
||||
```
|
||||
2. Implement the `ISwapAdapter` interface in the `./evm/src/<your-adapter-name>.sol` file.
|
||||
3. Create tests for your implementation in the `./evm/test/<your-adapter-name>.t.sol` file, again based on the template `./evm/test/TemplateSwapAdapter.t.sol`.
|
||||
Implement the `ISwapAdapter` interface in the `./evm/src/<your-adapter-name>.sol` file. There are two reference implementations, one for Uniswap V2 and the other for Balancer V2.
|
||||
|
||||
### Testing your implementation
|
||||
Clone the `evm/test/TemplateSwapAdapter.t.sol` file and rename it to `<your-adapter-name>.t.sol`. Implement the tests for your adapter, make sure all implemented functions are tested and working correctly. Look at the examples of `UniswapV2SwapAdapter.t.sol` and `BalancerV2SwapAdapter.t.sol` for reference. The [Foundry test guide](https://book.getfoundry.sh/forge/tests) is a good reference, especially the chapter for [Fuzz testing](https://book.getfoundry.sh/forge/fuzz-testing), which is used in both the Uniswap and Balancer tests.
|
||||
|
||||
We are using fork testing, i.e. we are running a local Ethereum node and fork the mainnet state. This allows us to test the integration against the real contracts and real data. To run the tests, you need to set the `ETH_RPC_URL` environment variable to the URL of an ethereum RPC. It can be your own node or a public one, like [Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/).
|
||||
|
||||
Finally, run the tests with:
|
||||
```bash
|
||||
cd ./evm
|
||||
forge test
|
||||
```
|
||||
|
||||
@@ -3,14 +3,13 @@ pragma experimental ABIEncoderV2;
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol";
|
||||
import "forge-std/Test.sol";
|
||||
|
||||
// Maximum Swap In/Out Ratio - 0.3
|
||||
// https://balancer.gitbook.io/balancer/core-concepts/protocol/limitations#v2-limits
|
||||
uint256 constant RESERVE_LIMIT_FACTOR = 4;
|
||||
uint256 constant SWAP_DEADLINE_SEC = 1000;
|
||||
|
||||
contract BalancerV2SwapAdapter is ISwapAdapter, Test {
|
||||
contract BalancerV2SwapAdapter is ISwapAdapter {
|
||||
IVault immutable vault;
|
||||
|
||||
constructor(address payable vault_) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
pragma experimental ABIEncoderV2;
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol";
|
||||
|
||||
/// @title TemplateSwapAdapter
|
||||
/// @dev This is a template for a swap adapter.
|
||||
/// Rename it to your own protocol's name and implement it according to the
|
||||
/// specification.
|
||||
contract TemplateSwapAdapter is ISwapAdapter {
|
||||
function price(
|
||||
bytes32 _poolId,
|
||||
IERC20 _sellToken,
|
||||
IERC20 _buyToken,
|
||||
uint256[] memory _specifiedAmounts
|
||||
) external view override returns (Fraction[] memory _prices) {
|
||||
revert NotImplemented("TemplateSwapAdapter.price");
|
||||
}
|
||||
|
||||
function swap(
|
||||
bytes32 poolId,
|
||||
IERC20 sellToken,
|
||||
IERC20 buyToken,
|
||||
OrderSide side,
|
||||
uint256 specifiedAmount
|
||||
) external returns (Trade memory trade) {
|
||||
revert NotImplemented("TemplateSwapAdapter.swap");
|
||||
}
|
||||
|
||||
function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken)
|
||||
external
|
||||
returns (uint256[] memory limits)
|
||||
{
|
||||
revert NotImplemented("TemplateSwapAdapter.getLimits");
|
||||
}
|
||||
|
||||
function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken)
|
||||
external
|
||||
returns (Capability[] memory capabilities)
|
||||
{
|
||||
revert NotImplemented("TemplateSwapAdapter.getCapabilities");
|
||||
}
|
||||
|
||||
function getTokens(bytes32 poolId)
|
||||
external
|
||||
returns (IERC20[] memory tokens)
|
||||
{
|
||||
revert NotImplemented("TemplateSwapAdapter.getTokens");
|
||||
}
|
||||
|
||||
function getPoolIds(uint256 offset, uint256 limit)
|
||||
external
|
||||
returns (bytes32[] memory ids)
|
||||
{
|
||||
revert NotImplemented("TemplateSwapAdapter.getPoolIds");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,8 @@ contract UniswapV2SwapAdapter is ISwapAdapter {
|
||||
return amountOut;
|
||||
}
|
||||
|
||||
/// @notice Given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
|
||||
/// @notice Given an input amount of an asset and pair reserves, returns the
|
||||
/// maximum output amount of the other asset
|
||||
/// @param amountIn The amount of the token being sold.
|
||||
/// @param reserveIn The reserve of the token being sold.
|
||||
/// @param reserveOut The reserve of the token being bought.
|
||||
@@ -173,7 +174,8 @@ contract UniswapV2SwapAdapter is ISwapAdapter {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/// @notice Given an output amount of an asset and pair reserves, returns a required input amount of the other asset
|
||||
/// @notice Given an output amount of an asset and pair reserves, returns a
|
||||
/// required input amount of the other asset
|
||||
/// @param amountOut The amount of the token being bought.
|
||||
/// @param reserveIn The reserve of the token being sold.
|
||||
/// @param reserveOut The reserve of the token being bought.
|
||||
|
||||
@@ -95,7 +95,8 @@ contract BalancerV2SwapAdapterTest is Test, ISwapAdapterTypes {
|
||||
if (side == OrderSide.Buy) {
|
||||
vm.assume(specifiedAmount < limits[1]);
|
||||
|
||||
// TODO calculate the amountIn by using price function as in testPriceDecreasing
|
||||
// TODO calculate the amountIn by using price function as in
|
||||
// testPriceDecreasing
|
||||
deal(address(BAL), address(this), type(uint256).max);
|
||||
BAL.approve(address(adapter), type(uint256).max);
|
||||
} else {
|
||||
|
||||
18
evm/test/TemplateSwapAdapter.t.sol
Normal file
18
evm/test/TemplateSwapAdapter.t.sol
Normal file
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "src/interfaces/ISwapAdapterTypes.sol";
|
||||
import "src/libraries/FractionMath.sol";
|
||||
|
||||
/// @title TemplateSwapAdapterTest
|
||||
/// @dev This is a template for a swap adapter test.
|
||||
/// Test all functions that are implemented in your swap adapter, the two test included here are just an example.
|
||||
/// Feel free to use UniswapV2SwapAdapterTest and BalancerV2SwapAdapterTest as a reference.
|
||||
contract TemplateSwapAdapterTest is Test, ISwapAdapterTypes {
|
||||
using FractionMath for Fraction;
|
||||
|
||||
function testPriceFuzz(uint256 amount0, uint256 amount1) public {}
|
||||
|
||||
function testSwapFuzz(uint256 specifiedAmount) public {}
|
||||
}
|
||||
@@ -73,7 +73,8 @@ contract UniswapV2PairFunctionTest is Test, ISwapAdapterTypes {
|
||||
if (side == OrderSide.Buy) {
|
||||
vm.assume(specifiedAmount < limits[1]);
|
||||
|
||||
// TODO calculate the amountIn by using price function as in BalancerV2 testPriceDecreasing
|
||||
// TODO calculate the amountIn by using price function as in
|
||||
// BalancerV2 testPriceDecreasing
|
||||
deal(address(USDC), address(this), type(uint256).max);
|
||||
USDC.approve(address(adapter), type(uint256).max);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user